find + xargs:参数行太长


21

我有如下一行:

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

但出现以下错误:

xargs: argument line too long

我很困惑。使用不是xargs应该精确地解决这个问题吗?

注意:我知道我可以-exec在find中使用技术,但是我想理解为什么上面的方法失败,因为我的理解xargs是应该知道如何将输入拆分为可管理的大小,以适应其运行的参数。这不是真的吗

这就是zsh的全部。

Answers:


11

好吧,-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 /foot/bar/ -name '*.mp4' -exec mv -t /some/path {} +

谢谢!当您说"This approach shouldn't be used"应该使用哪种方法代替时?会"find /foot/bar/ -name '*.csv' -print0 | xargs -0 mv -t some_dir'"是更好的解决方案吗?如果是这样,怎么xargs知道在这种情况下的mv命令,它从管道得到的参数进?(是否总是将它们放置在最后?)
阿梅利奥·瓦兹奎兹·雷纳

@ user815423426 -用做它只是find ... -exec ...一个更好的办法,或者如果你想使用xargsfind ... | xargs ... mv -t ...是也没关系。是的,它总是把他们放在最后。这就是为什么该方法需要的原因-t
slm

5

该选项-i带有一个可选参数。由于您在其后放置了一个空格-i-i因此该选项没有参数,因此后-0一个选项不是选项,xargs而是6个操作数中的第二个{} -0 mv -t /some/path {}

仅使用选项-i,xargs期望以换行符分隔的文件名列表。由于输入中可能没有换行符,因此xargs收到的文件名看起来像个很大的文件名(带有嵌入的空字节,但xargs并未检查该文件名)。包含整个输出的单个字符串find比最大命令行长度长,因此出现错误“命令行太长”。

您的命令将-i{}代替一起使用-i {}。另外,您可能使用了-I {}-I类似于-i,但采用了必填参数,因此传递给的下一个参数xargs用作该-I选项的参数。然后,后面的参数-0被解释为选项,依此类推。

但是,您根本不应该使用-I {}。使用-I具有三个效果:

  • -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 {} +

0

尝试使用bash进行循环:

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

或者,如果您想查看发生了什么事情:

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

0

如果您在使用见状鱼贝
这与鱼如何扩展替换字符串有关{}

如果您使用的是鱼,则需要避开替换字符串 \{\}

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

或使用其他替换字符串

| xargs -I ! echo !
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.