私は今日、ランチ時にディレクトリ内の拡張子のないファイルを見つけて、そのファイルにファイル拡張子を追加するbashスクリプトを作成しました。
複数のフラグとディレクトリの選択、ファイルのコピー、または上書きなどを追加したため、スクリプトは比較的長いですが、実行する作業の主な要旨は、次のように簡単に複製できます。
#recursively find files in current directory that have no extension
for i in $(find . -type f ! -name "*.*"); do
#guess that extension using file
extfile=$(file --extension --brief $i)
#select the first extension in the event file spits something weird (e.g. jpeg/jpe/jfif)
extawk=$(echo $extfile | awk -F/ '{print $1}')
#copy the file to a file appended with the extension guessed from the former commands
cp -av $i $i.$extawk
done
私の本当のスクリプトでは少しきれいです。ここでコマンドを分割して、なぜこのようにしたのかを説明できるようにしたいと思いました。
私の質問:私が選択した方法でfind
組み合わせることがfile
最も簡単な方法ではないかもしれません。最高複数のディレクトリにあるさまざまなファイル形式の拡張子を再帰的に推測して追加する方法は?
ベストアンサー1
for x in $(find …)
失敗したスペース(一般)またはワイルドカード(一般的ではない)を含むファイル名。find
.useを解析しないでください-exec
。
必要なタスクを実行するzmvコマンドを作成しましょう。まず、検索パターンを構築してみましょう。
autoload zmv
zmv -C -o -a -n -Q '(*/)#^*.*(.)' …
-C
ファイルを移動する代わりにコピーします。-o -a
-a
に渡されましたcp
。-n
何もしないで実行するジョブだけを印刷することを意味します。満足のいくものを削除してください。-v
ジョブを実行したいが、実行中のジョブも印刷するには、に置き換えます。-Q
作るグローバル予選パターンから。(*/)#
0個以上のディレクトリと一致します。それを使う#
グローバルオペレータ(extended_glob
zmvでは常に有効です)。^*.*
名前にaが含まれていないファイルを^
一致させるには、glob演算子を使用してください。.
(.)
一般ファイルの一致を制限するglob修飾子です。…
代替テキストに置き換えられます。これは$f
元の名前を参照するために使用できます。
zmv
すべての代替名は、置換が実行される前に評価され、代替名が既に存在または競合している場合はエラーが表示されます。代替名が元の名前と同じファイルはスキップされます。
それでは、代替テキストを書いてみましょう。私たちはたくさん使うでしょうパラメータ拡張特徴。
file
延長をリクエストしてください。$(file --extension --brief -- $f)
- 前に1つ追加
.
、交換の準備:($(echo -n .; file --extension --brief -- $f)
パラメータ拡張を介して行うこともできます。${:-.$(…)}
) - 提案された拡張子が複数ある場合(スラッシュで区切られた場合)、最初の拡張子のみが保持されます。
${$(echo -n .; file --extension --brief -- $f)%%/*}
- 提案された拡張子が空の場合、または
???
削除されます(.
または.???
空の文字列で置き換えます)。${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}
- 追加された拡張子を
$f
(元の名前)に追加します。追加した内容が空の場合、ファイルは変更されていません。
結果コマンド:
zmv -C -o -a -n -Q '(*/)#^*.*(.)' '$f${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}'
これは少し難しく、置換を生成するコードを関数に入れてzmv … '$(add_extension $f)'
。