「xargs」と「file」の奇妙な「対応するファイルなし」エラー

「xargs」と「file」の奇妙な「対応するファイルなし」エラー

現在のディレクトリにあるすべてのファイルのMIMEタイプを取得したいと思います。なぜこれがうまくいかないのですか? OSXまたはLinuxでbashをテストしました。 「ファイル」はファイルが見つからないと文句を言いますが、まったく同じパスを使用して実行すると機能します。

$ find . -type f | xargs -n 1 -I FILE echo $(file --mime-type -b FILE)
ERROR: cannot open './foo.txt' (No such file or directory)
...
$ file --mime-type -b ./foo.txt
text/plain

もちろん、実際の世界では、応答を「エコー」するのではなく、他のコマンドでMIMEタイプの文字列を使用する必要があります。

これが私が解決できる最も簡単な問題です。ファイル名の置き換えについて何かを理解していないと思いますかxargs

答え1

コマンドの置き換え$(file --mime-type -b FILE)は に渡される前にシェルによって実行されるため、xargs必要なものは表示されません。 xargsを介して引用して$(file --mime-type -b FILE)渡します。bash -c

find . -type f | xargs -n 1 -I FILE bash -c  'echo $(file --mime-type -b FILE)'

答え2

ここでは悪用する必要はありませんxargsfindスイッチを使用してください-exec

$ find . -type f -exec file --mime-type -- {} +

はい

基本file出力

$ find 8* -type f -exec file --mime-type -- {} + | tail -5
89999/sample10.txt:               text/plain
89999/sample2.txt:                text/plain
89999/sample4.txt:                text/plain
89999/sample6.txt:                text/plain
89999/sample9.txt:                text/plain

file -b出力

$ find 8* -type f -exec file --mime-type -b -- {} + | head -5
application/x-empty
text/x-perl
text/plain
text/plain
text/plain

代替

mimetypeこれは参考用ですが、同じ操作を実行するために使用できる別のコマンドがありますfile --mimetype。このコマンドはFedoraのこのパッケージの一部であり、同様にperl-File-MimeInfo機能します。

$ find 8* -type f -exec mimetype -- {} + | tail -5
89999/sample10.txt:               text/plain
89999/sample2.txt:                text/plain
89999/sample4.txt:                text/plain
89999/sample6.txt:                text/plain
89999/sample9.txt:                text/plain

より詳細な実装

「単にecho..以上」について質問し、..を使用しようとしていることを考えると、..をxargs使用する必要があると思うという結論を下しますxargs

ただし、を使用している場合、findこれは通常最善のアプローチではありません。より複雑な方法でこれを行うのではなく、スイッチでfindシェルを使用して呼び出すことで、より複雑な操作を実行できます。find-execxargs

$ find . -type f -exec sh -c '
   cmd1;
   cmd2;
   file --mime-type -b "$@";
   cmd3;
   cmd4;
 ' sh {} \;

メモ:+複数のパラメータを渡すターミネータを使用することから、file --mime-type ...一度に1つのパラメータを渡すことに切り替えました\;

はい

$ find 8* -type f -exec sh -c '
   echo -n "mime-type: "; 
   file --mime-type -b "$@"
  ' sh {} \; |& tail -10
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/x-shellscript
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain

答え3

あなたの問題はシェル拡張に関連しています。 $() は引数として渡される前に拡張されます。現状のまま処理するには、一重引用符で囲み、シェルを呼び出します。

また、ファイル名を扱う場合は、print0と0を使用する習慣を持ちます。これを省略すると、空白文字を含むファイル名に問題が発生する可能性があります。

例:

find . -type f -print0 | xargs -0 -n 1 -I FILE bash -c 'echo $(file --mime-type -b FILE)'

あなたの場合、これは次のように単純化することができます。

find . -type f -print0 | xargs -0 -n 1 file --mime-type -b

追加の説明:見つかったすべてのファイル( "xargs -n 1"またはfind + exec)に対してプログラムを呼び出すと、実際のパフォーマンスのボトルネックが発生する可能性があります。ディレクトリに何千ものファイルが含まれている場合、何千ものプロセスが作成されます。

関連情報