今日、昼休みに、ディレクトリ内の拡張子のないファイルを検索し、それらのファイルにファイル拡張子を追加する 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
でinとinを組み合わせて使用することは、おそらくこれを実行するための最も確実な方法ではないでしょう。file
最高複数のディレクトリ間で多様なファイルタイプの一括グループの拡張子を再帰的に推測して追加する方法はありますか?
答え1
for x in $(find …)
失敗する空白文字(一般的)またはワイルドカード文字(あまり一般的ではない)を含むファイル名. の出力を解析しないでくださいfind
。 を使用してください-exec
。
必要なことを実行する zmv コマンドを作成しましょう。まず、検索パターンを構築しましょう。
autoload zmv
zmv -C -o -a -n -Q '(*/)#^*.*(.)' …
-C
ファイルは移動されるのではなくコピーされます。-o -a
-a
に渡されますcp
。-n
は何も実行せず、実行される内容を印刷するだけを意味します。満足したら削除してください。-v
実行しながらも実行される内容を印刷したい場合は、 に置き換えてください。-Q
有効にするglob 修飾子パターンで。(*/)#
0個以上のディレクトリに一致します。#
グロブ演算子(extended_glob
zmv では常に有効になっています)。^*.*
glob 演算子を使用して、名前に^
a を含まないファイルを一致させます。.
(.)
一致を通常のファイルに制限する glob 修飾子です。…
置換テキストに置き換えられます。これを使用して$f
元の名前を参照できます。
zmv
置換を実行する前にすべての置換名を計算し、置換名がすでに存在する場合や競合がある場合はエラーを出力します。置換名が元のファイルと同一であるファイルはスキップされます。
では、置換テキストを作成しましょう。パラメータ拡張特徴。
file
延長を依頼する:$(file --extension --brief -- $f)
.
置換の準備として、を先頭に付加します:$(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)'
。
答え2
最も効果的な方法は、ファイルの MIME タイプを にあるデータベースと比較することだと思います/usr/share/mime/globs
。
- グロブLinuxではファイル拡張子. 例として、出力は次の通りですglobs ファイル
application/x-mswinurl:*.url
text/x-mrml:*.mrl
text/x-erlang:*.erl
audio/x-pn-audibleaudio:*.aa
application/x-bzip-compressed-tar:*.tbz2
application/x-netshow-channel:*.nsc
application/x-hdf:*.h4
application/pgp-keys:*.key
text/x-idl:*.idl
text/x-chdr:*.h
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.visio:*.vsd
application/x-hdf:*.h5
video/vnd.mpegurl:*.m4u
- 型の例を記述した後 -->
text/x-erlang
、Linuxにすべてのファイルを*.
次のように識別するように指示します。アーラン拡張子.erl
[glob]が付いているので、 -->*.erl
/etc/magic
ファイルにカウントされる独自の拡張子を追加できます
次のコマンドを実行します:
mimetype -bM file
b
単に見せるだけの議論type-app/extension
(簡潔)M
議論は意味する魔法Linux がバイトコード、16 進数、バイナリでファイルをチェックアウトし、ファイルが実際にそのとおりのものであるかどうかを確認する方法です。MIMEタイプ返さないのは
/jpg/png/webp
1つの型のみを返し、より短いですfile --mime-type file
戻り値:
image/webp
最終的な考え
mimetype
最も効果的バイナリファイルPDF、画像、ビデオなどです。これはバイナリをチェックできるためですが、text plain
バイナリではなく、何かを識別する必要があり、これはより複雑です。そのため、テキスト エディターはさまざまなプログラミング言語を認識できますが、ユーザーからの支援と各プログラミング言語のサーバー言語が必要です。
再帰については、木結構です:
tree -FIi '*.*' | grep -v /$
- 引数はディレクトリに[スラッシュ]
F
を追加することです。例、 →/
folder
folder/
- 引数は
I
パターンの反対を選択することです*.*
[これは拡張子を持つすべてのファイルを選択することを意味します]。したがって、反対は拡張子ではありません。 - 引数は
i
ツリー出力からスペースを削除することです grep -v
逆を選択することです。そのため、-F/
引数を追加します木コマンドを先頭に追加すると、ディレクトリを削除してファイルのみを取得できます/$
。
詳細はこちらMIMEタイプ