复制大量文件时,“参数列表太长”错误

我正在使用以下命令:

\cp -uf /home/ftpuser1/public_html/ftparea/*.jpg /home/ftpuser2/public_html/ftparea/ 

我得到的错误:

 -bash: /bin/cp: Argument list too long 

我也试过了:

 ls /home/ftpuser1/public_html/ftparea/*.jpg | xargs -I {} cp -uf {} /home/ftpuser2/public_html/ftparea/ 

还有-bash:/ bin / ls:参数列表太长了

有任何想法吗?

* .jpg扩展为比shell可以处理更长的列表。 试试这个

 find /home/ftpuser/public_html/ftparea/ -name "*.jpg" -exec cp -uf "{}" /your/destination \; 

系统命令的参数列表可以有多长时间限制 – 这个限制是在内核被编译时基于MAX_ARG_PAGES的值进行的特定于发行版的,并且在不重新编译内核的情况下不能更改。

由于shell处理globbing的方式,当你使用相同的参数(“* .jpg”)时,这会影响大多数系统命令。 由于glob首先由shell处理,然后发送给命令,命令:

 cp -uf *.jpg /targetdir/ 

基本上和shell一样,如果你写了:

 cp -uf 1.jpg 2.jpg ... n-1.jpg n.jpg /targetdir/ 

如果你正在处理大量的jpeg,这可能会很快变得难以pipe理。 根据您的命名约定和您实际上必须处理的文件数量,您可以一次在目录的不同子集上运行cp命令:

 cp -uf /sourcedir/[am]*.jpg /targetdir/ cp -uf /sourcedir/[nz]*.jpg /targetdir/ 

这可以工作,但究竟是多么有效的基础上,你可以如何把你的文件列表打破方便globbable块。

Globbable。 我喜欢那个词。

一些命令(如findxargs )可以处理大型文件列表,而不需要制作令人难以忍受的参数列表。

 find /sourcedir/ -name '*.jpg' -exec cp -uf {} /targetdir/ \; 

-exec参数将为查找到的每个文件运行一次命令行的其余部分,用每个find的文件名replace{}。 由于cp命令一次只能在一个文件上运行,因此参数列表限制不是问题。

由于必须分别处理每个文件,这可能会很慢。 使用xargs可以提供更高效的解决scheme:

 find /sourcedir/ -name '*.jpg' -print0 | xargs -0 cp -uf -t /destdir/ 

xargs可以将find提供的完整文件列表分解为可pipe理大小的参数列表,并在每个子列表上运行cp

当然,也可以重新编译内核,为MAX_ARG_PAGES设置一个更大的值。 但重新编译一个内核比我愿意在这个答案中解释更多的工作。

发生这种情况是因为通配符expression式( *.jpg )在展开时超出了命令行参数长度限制(可能是因为在/home/ftpuser/public_html/ftparea下有很多.jpg文件)。

有几种方法来规避这个限制,比如使用find或者xargs 。 看看这篇文章的更多细节如何做到这一点。

有一个可以指定给程序的最大数量的参数,bash将* .jpg展开为cp的很多参数。 你可以使用find,xargs或者rsync等来解决它。

看看这里关于xargs并find

https://stackoverflow.com/questions/143171/how-can-i-use-xargs-to-copy-files-that-have-spaces-and-quotes-in-their-names

正如GoldPseudo所评论的那样,可以传递给您产生的进程的参数有多less。 请参阅他的答案,以便对该参数进行很好的描述。

您可以通过不传递过多的参数或减less传递的参数数量来避免这个问题。

在shell中的for循环,find和ls,grep和while循环在这种情况下都做同样的事情 –

 for file in /path/to/directory/*.jpg ; do rm "$file" done 

 find /path/to/directory/ -name '*.jpg' -exec rm {} \; 

 ls /path/to/directory/ | grep "\.jpg$" | while read file do rm "$file" done 

都有一个程序读取目录(shell本身,find和ls)和一个不同的程序, 每个程序实际上只需要一个参数,并遍历整个命令列表。

现在,这将是缓慢的,因为需要为每个匹配* .jpg模式的文件分配和执行。

这是xargs进场的地方。 xargs需要标准input,对于每个N(对于freebsd来说,默认是5000)行,它会产生一个带有N个参数的程序。 xargs是上述循环的优化,因为你只需要fork 1 / N程序来遍历从命令行读取参数的整个文件集合。

'*'glob正在扩展到太多的文件名。 改用find / home / ftpuser / public_html -name'* .jpg'。

使用+选项来find -exec将大大加速操作。

 find /home/ftpuser/public_html/ftparea/ -name "*jpg" -exec cp -uf -t /your/destination "{}" + 

+选项需要{}作为最后一个参数,所以使用-t /your/destination (或--target-directory=/your/destination )选项来使cp正常工作。

man find

-exec命令{} +

  This variant of the -exec action runs the specified command on the selected files, but the command line is built by appending each selected file name at the end; the total number of invoca‐ tions of the command will be much less than the number of matched files. The command line is built in much the same way that xargs builds its command lines. Only one instance of '{}' is allowed within the command. The command is executed in the starting directory. 

编辑 :重新排列参数到CP

这听起来像是你的目录中有太多的*.jpg文件将它们全部放在命令行上。 你可以尝试:

 find /home/ftpuser/public_html/ftparea1 -name '*.jpg' | xargs -I {} cp -uf {} /home/ftpuser/public_html/ftparea2/ 

您可能需要检查man xargs以确定您的系统是否正确。

其实,你真的打算把这些文件复制到他们已经在的地方吗?

转到文件夹

 cd /home/ftpuser1/public_html/ 

并执行以下操作:

 cp -R ftparea/ /home/ftpuser2/public_html/ 

通过这种方式,如果文件夹“ftparea”有子文件夹,这可能是一个负面影响,如果你只想从它的'* .jpg'文件,但如果没有任何子文件夹,这种方法肯定会比使用find和xargs