web-dev-qa-db-ja.com

find + xargs:引数行が長すぎます

次のような行があります。

find /foo/bar -name '*.mp4' -print0 | xargs -i {} -0 mv -t /some/path {}

しかし、私は次のエラーを受け取りました:

xargs: argument line too long

私は混乱しています。 xargsの使用は、この問題に正確に役立つはずではありませんか?

注:技術的に-exec in findですが、xargsは入力を実行可能な引数に管理可能なサイズに分割する方法を知っているはずなので、上記が失敗する理由を理解したいと思います。これは本当ではないですか?

これはすべてzshの場合です。

22

まず、-iスイッチは廃止されました。

-i[replace-str]
     This  option  is a synonym for -Ireplace-str if replace-str is specified. 
     If the replace-str argument is missing, the effect is the same as -I{}. 
     This option is deprecated; use -I instead.

だから私があなたのコマンドをこれに変えたとき、それはうまくいきました:

$ find /foo/bar -name '*.mp4' -print0 | xargs -I{} -0 mv -t /some/path {}

$ find . -print0 | xargs -I{} -0 echo {}
.
./.sshmenu
./The GIT version control system.html
./.vim_SO
./.vim_SO/README.txt
./.vim_SO/.git
./.vim_SO/.git/objects
./.vim_SO/.git/objects/pack
./.vim_SO/.git/objects/pack/pack-42dbf7fe4a9b431a51da817ebf58cf69f5b7117b.idx
./.vim_SO/.git/objects/pack/pack-42dbf7fe4a9b431a51da817ebf58cf69f5b7117b.pack
./.vim_SO/.git/objects/info
./.vim_SO/.git/refs
./.vim_SO/.git/refs/tags
...

-I{}の使用

次のコマンド構成を実行するため、このアプローチは使用しないでください。

$ find -print0 ... | xargs -I{} -0 ...

これらのスイッチを暗黙的にxargs-x-L 1に切り替えます。 -L 1は、xargsを構成して、単一の方法でファイルを実行するコマンドを呼び出すようにします。

したがって、ここでxargsを使用する目的は無効になります。1000個のファイルを指定すると、mvコマンドが1000回実行されるためです。

では、どのアプローチを使用すればよいですか?

次のようにxargsを使用して実行できます。

$ find /foot/bar/ -name '*.mp4' -print0 | xargs -0 mv -t /some/path

または、単にfind all it do all:

$ find /foot/bar/ -name '*.mp4' -exec mv -t /some/path {} +
12
slm

オプション-iはオプションの引数を取ります。 -iの後にスペースを置いたため、-iオプションに引数がなかったため、後続の-0xargsのオプションではなく、6つのオペランドの2番目{} -0 mv -t /some/path {}

オプション-iのみを指定すると、xargsは改行で区切られたファイル名のリストを予期していました。おそらく入力に改行がないため、xargsは巨大なファイル名のように見えるものを受け取りました(nullバイトが埋め込まれていますが、xargsはそれをチェックしませんでした)。 findの出力全体を含むこの単一の文字列は、コマンドラインの最大長よりも長いため、「コマンドラインが長すぎます」というエラーが発生します。

コマンドは-i{}ではなく-i {}で機能します。または、-I {}を使用することもできます:-I-iに似ていますが、必須の引数を取るため、xargsに渡される次の引数が引数として使用されます-Iオプションのその後の引数は、オプションとして解釈される-0などです。

ただし、-I {}は使用しないでください。 -Iを使用すると、3つの効果があります。

  • -Iは、引用処理をオフにします。これは、-0ですでに行われています。
  • -Iは、置換する文字列を変更しますが、{}がデフォルト値です。
  • -Iを指定すると、コマンドは入力レコードごとに個別に実行されます。コマンド(mv -t)は、呼び出しごとに複数のファイルに対処することを目的としているため、ここでは役に立ちません。

-I-iを完全に削除する

find /foo/bar -name '*.mp4' -print0 | xargs -0 mv -t /some/path {}

または、xargsをドロップして-execを使用します。

find /foo/bar -name '*.mp4' -exec mv -t /some/path {} +

Bash forループを使用してみてください:

for FILE in *.mp4 ; do rm $FILE ; done

または、何が起こっているのかを見たい場合:

for FILE in *.mp4 ; do echo Removing $FILE ; rm $FILE ; done
0
C. Shamis

fish Shell の使用中にこれが表示された場合。
これは、fishが置換文字列{}を拡張する方法に関連しています

魚を使用している場合は、置換文字列\{\}をエスケープする必要があります

| xargs -I \{\} echo \{\}

または別の置換文字列を使用する

| xargs -I ! echo !
0
nelaaro