小さなものから

小さなものから

私はこれに慣れておらず、このシェルスクリプトを書く方法を知りたいです。

ディレクトリ1にファイル名を持つファイルがあり、ファイル名の2番目の部分に基づいてA1-001.xyz A29-002.xyz A82-003.xyzこのファイルをディレクトリ2に移動したいと思います。フォルダ名は001 002 003です。001 002 003

これまで私がしたことは次のとおりです。

for file in /path/to/directory1/** ; do
echo "$file" | awk -F '[-]' '{print $2}' | cut -f 1 -d '.' ;
done >> dummy.txt 

input="dummy.txt"
while IFS= read -r file; do
echo "$file" | mv "$file" /path/to/directory2/$file ;
done 

私の考えは、出力ファイル名の最初の部分をdummy.txtに入れてから、ファイル名を読み取って移動することです。スクリプトの2番目の部分が機能していないようです。これを行う方法に関する提案はありますか?

ベストアンサー1

小さなものから

問題をより小さな部分に分割します。詰まっている理由の1つは、ソリューション自体を構築するために使用されるツールを操作する方法を学ぶことを試みながら、ソリューション全体を一度に構築しようとすることです。

ここにトラブルシューティングに役立つヒントがあり、後で同様の問題を分析して分析する必要があるときに、他の初心者のスクリプターが役立つヒントがあることを願っています。

各ファイルに対して実行する必要がある操作の正確な特性を指定することから始めます。実際には、ファイルリストからサンプリングされた1つの特定のファイル名を処理するために必要なコマンドを手動で作成できる必要があります。 機能せずにコマンドのみを作成します。あなたの例では、すべてのファイルを移動する必要があります。そうですか?したがって、各ファイルにはmvコマンドが必要です。何をすべきか心配するのではなくするコマンドmvを生成する方法だけを心配してください。手動でどのように作成しますか?一つmvファイルを移動するコマンドは何ですか?これにより、質問はawkこのコマンドをどのように(または使用したいツール)出力するかになります。

mv (filename) (to-where-you-want-it)

指定したファイル名ごとに。新しいツールを学ぶことで、実際に実行せずに一連のシェルコマンドを出力として生成するスクリプトをデバッグする方が簡単です。行為横に移動し、何百もの間違ったファイルを何百もの間違ったディレクトリに移動するスクリプトをデバッグするよりも重要なことはありません。今はどこがどこにあるのか分からない。

まず、manあなたに適していると思われるツールのページを確認してください。次に、手動モードでコマンドを試して、ツールに入力を必要な方法で解析し、必要な出力を生成させるために何をすべきかについてのアイデアを得ます。 100個または1000個のファイルを移動するスクリプトを作成する前に、そのファイルを正しく移動するスクリプトが必要です。単一文書。したがって、テストケースを作成し、効果があると思われるツールを使用して「友達を作る」時間を過ごしてください。あなたの投稿がタグ付けされました賢い選択だと思うのでやってみよう。

awk文字列をコンポーネントフィールドに分割するために使用される区切り文字を-F指定するために使用できるパラメータがあります。awk区切り文字は、単純な文字でもかっこで囲まれた複数の文字でもかまいません。正規表現の用語では、これは次のとおりです。キャラクタークラス。入力では、ハイフン'-'とピリオドの両方をフィールド区切り文字として使用するため、ハイフンまたはピリオドに分割するように指示する'.'文字クラスを指定できます。どちらが何であるかは気にせず、ソースディレクトリにハイフンやピリオドが含まれていないことを慎重に確認してください。[-.]awkawk

awk各ファイル名をコンポーネントフィールドに分割するために使用されます。

ファイル名の例を取得し、このコマンドを使用して手動で実行して、ファイル名が何をしているのかをA1-001.xyz確認awkします。awk

$ awk -F[-.] '{print $0 " " $1 " " $2 " " $3}' <<< 'A1-001.xyz'

コマンドは次のように言いますawk。 「ハイフンとピリオドをフィールド区切り文字として使用して、入力行全体($0)、スペース、フィールド1、スペース、フィールド2、スペース、最後にフィールド3を印刷します。

出力は次のとおりです

A1-001.xyz A1 001 xyz

これがあなたに多くを示してくれることを願っています。これはコマンドのソースから必要なもの$0です。なぜなら、それは完全な元のファイル名だからです。これはあなたが望む数字ディレクトリ名なので、コマンドのターゲットに必要なものです。最大の実装は、完全にフォーマットして印刷できるコマンドです。必要なのは少し修正された文だけです。スクリプトがすべてをやろうとするのではなく、スクリプトにすべてをさせます。mv$2mvawkmvawkprint作る実行する必要があるコマンドです。これにより、スクリプトのエラーによってスクリプトがクラッシュし、ファイルが間違った場所に移動されなくなります。いくつかの誤った出力を印刷すると、それが間違っていることがわかりますが、害はありません。

awk精製コマンドの2回目の繰り返し

ファイル名の前にはソースパスが続くことがあります。しかし、.パスにまたは文字がないことを確認してください!-したがってmv、各ファイルのコマンドはmvスペースで始まり、ファイル名(フルソースパスを含めることができます)、他のスペース、およびファイルを移動するディレクトリで始まります。良い測定のために、ターゲットディレクトリの後ろにスラッシュを追加します。あなたが以来いいえファイル名を変更するには、宛先ディレクトリを指定して宛先ファイル名を省略します。また、実行する方が簡単なので注目に値する。必要以上に仕事を難しくしないでください。

$ awk -F[-.] '{print "mv " $0 " " $2 "/"}' <<< '/path/to/directory1/A1-001.xyz'
mv /path/to/directory1/A1-001.xyz 001/

コマンドを見てくださいprint。スペースで始まりmv$0ファイル名全体がスペースとして表示されます。これは$2出力サブディレクトリです。もう一度ソースパス名を解決する必要があります。欲しくないファイル名のフィールド区切り文字として特別な意味を持つため、ハイフンやピリオドを含めます。さらに問題があります。awkフィールドが正しく分割されないため、スクリプトが中断されます。

ただし、ターゲットディレクトリは単なるものではなく、$2ソースファイル名と同様に前にプレフィックスがあります。awk毎回同じので印刷できます。

$ awk -F[-.] '{print "mv " $0 " /path/to/directory2/" $2 "/"}' <<< '/path/to/directory1/A1-001.xyz'
mv /path/to/directory1/A1-001.xyz /path/to/directory2/001/

完全なファイルリストからソリューションをテストする

だからこれは有望に見えます。これでファイルリストを作成しますfile-list.txt

$ cat file-list.txt 
A1-001.xyz
A29-002.xyz
A82-003.xyz

次に、awkファイル全体のリストに対してコマンドを実行します。ここでは悪いことがまったくないことを覚えておいてください。awk完了したすべてのタスクは次のとおりです。印刷もの。実際、ファイルの移動については何もしません。単にあなたがしたいことをするコマンドを見せるだけです。

$ awk -F[-.] '{print "mv " $0 " /path/to/directory2/" $2 "/"}' < file-list.txt 
mv A1-001.xyz /path/to/directory2/001/
mv A29-002.xyz /path/to/directory2/002/
mv A82-003.xyz /path/to/directory2/003/

出力を再確認し、テストして実行します。

移動するファイルが多い場合は、awk上記のコマンドをパイプで接続してless再確認できる必要があります。間違った場所にドットとダッシュがあるか、ファイルまたはディレクトリ名に別の奇妙な文字があるかどうかを確認してください。必要に応じて、この出力のサンプルラインをコピーしてシェルプロンプトに貼り付けて、正しく機能していることを確認できます。ただし、これはテストでテストするのに十分簡単な例です。このmvコマンドのリストが目的のジョブであることを確認したら、awk出力を直接パイプしてsh実行するだけです。実行されるコマンドを表示するには、sh -v次の代わりに使用しますsh

$ awk -F[-.] '{print "mv " $0 " /path/to/directory2/" $2 "/"}' < file-list.txt | sh -v
mv A1-001.xyz /path/to/directory2/001/
mv A29-002.xyz /path/to/directory2/002/
mv A82-003.xyz /path/to/directory2/003/
$

結論として

このように詳細な分析に反対しなかったらと思います。しかし、このような質問はStack Exchangeに頻繁に登場し、多くの初心者のスクリプターは、独自の問題が独自のソリューションを必要とする独自のワンタイム問題だと思います。

スクリプトの真の鍵は、スクリプトがさまざまな問題を解決するための一般的なツールを提供することに気付くことです。経験を得るための最初のステップは、これらのツールを使用して小さなタスクを実行する方法を学び、その小さなタスクをますます大きなタスクにまとめることです。もの。

awk最初のステップは、ファイル名を必要な方法で分離する方法を学ぶことです。これは、複数の情報を含むファイル名からコンポーネントフィールドを解析しようとするたびに重要な手順です。

2番目のステップは、awkに、各ファイルに対して常に同じコマンド部分(フィールドの前の開始mv 、ターゲットパス)を自動的に印刷し、抽出されたファイル名フィールドを正しい場所に配置するように指示することです。ステートメントとその類似体は、あらゆるタイプのコーディングの最も基本的な部分の1つであり、適切なステートメントが原因で多くの損傷が発生したことを覚えていません。確かに必要なものだけを出力したいのですが、学習しながら変数が何なのかわからない場合は印刷してみてください。聞くのも悪くありません。長期的には、対応する印刷ステートメントを削除することになりますが、スクリプトの「印刷後のシェルへのパイプ」技術の要点は、「テスト実行」が組み込まれていることです。なぜなら、常に何が起こるのかを見るからです。実際にスクリプトをシェルにパイプする前に実行する前に、スクリプトのシェルコマンド出力を確認してください。複雑なケースでは、「タスクを表示」するために出力に説明を追加することも公平なゲームです。$2printprint

$ awk -F[-.] '{print "# move file " $0 " to subdir " $2; print "mv " $0 " /path/to/directory2/" $2 "/"}' < file-list.txt 
# move file A1-001.xyz to subdir 001
mv A1-001.xyz /path/to/directory2/001/
# move file A29-002.xyz to subdir 002
mv A29-002.xyz /path/to/directory2/002/
# move file A82-003.xyz to subdir 003
mv A82-003.xyz /path/to/directory2/003/

3番目の鍵は、2番目のポイントと密接に関連している可能性がありますが、見落とされることの1つは、少し難しいことをしているときに間違っている可能性があるスクリプトを書くのではなく、そのままにすることです。ファイルは数え切れないほど多様ですが、間違った場所に散在しています。ただスクリプトを書くスクリプトタスクを実行します。これにより、トラブルシューティングがはるかに簡単になります。その後、最終的に正しいスクリプトを取得したら、スクリプト出力(例では、mv各ファイルに対して1つずつ一連のコマンド)をシェルにパイプすることで実行されます。

おすすめ記事