rm,cp,mv命令的参数列表太长错误

Vic*_*cky 584 unix linux command-line-arguments

我在UNIX的目录下有几百个PDF.PDF的名称非常长(大约60个字符).

当我尝试使用以下命令一起删除所有PDF时:

rm -f *.pdf
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

/bin/rm: cannot execute [Argument list too long]
Run Code Online (Sandbox Code Playgroud)

这个错误的解决方案是什么?这个错误是否也出现在命令mvcp命令中?如果是,如何解决这些命令?

DPl*_*usV 807

发生这种情况的原因是因为bash实际上将星号扩展到每个匹配的文件,从而产生一个非常长的命令行.

试试这个:

find . -name "*.pdf" -print0 | xargs -0 rm
Run Code Online (Sandbox Code Playgroud)

警告:这是一个递归搜索,也会在子目录中找到(和删除)文件.-f只有在您确定不需要确认时才能使用rm命令.

您可以执行以下操作以使命令非递归:

find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用find的-delete标志:

find . -name "*.pdf" -delete
Run Code Online (Sandbox Code Playgroud)

  • Find有一个`-delete`标志来删除它找到的文件,即使它没有,仍然认为使用`-exec`来执行rm,而不是调用xargs(现在是3个进程和管道而不是带有`-delete`的单个进程或带有`-exec`的2个进程). (49认同)
  • 不,`xargs`专门拆分列表并在必要时发出几个命令. (7认同)
  • @Dennis:`-maxdepth 1`需要是路径后面的第一个参数. (7认同)
  • @scragar使用`-exec`调用`rm`,进程数将是1 +文件数,尽管从这个进程的并发进程数可能是2(也许find会同时执行rm进程).使用`xargs`的进程数量将大幅减少到2 + n,其中n是一些数字进程少于文件数(比如文件数/ 10,尽管可能更多取决于路径的长度).假设find直接删除,使用`-delete`应该是唯一可以调用的进程. (4认同)
  • @ÉdouardLopez...但这是读取NULL分隔的输入.整个'危险(破碎,可利用等)`,是相当荒谬的.毫无疑问,在使用`xargs`时你应该小心,但它不是'eval/evil`. (3认同)

Édo*_*pez 358

TL;博士

这是对命令行参数大小的内核限制.请改用for循环.

问题的根源

这是一个系统问题,与之相关execve并且ARG_MAX不变.有很多关于这方面的文档(参见man execve,debian的wiki).

基本上,扩展产生超过限制的命令(及其参数)ARG_MAX.在内核上2.6.23,限制设置为128 kB.这个常量已经增加,你可以通过执行以下方法获得它的值:

getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic
Run Code Online (Sandbox Code Playgroud)

解决方案:使用for循环

forBashFAQ/095上建议使用循环,除RAM /内存空间外没有限制:

for f in *.pdf; do rm "$f"; done
Run Code Online (Sandbox Code Playgroud)

这也是一种可移植的方法,因为glob在shell中具有强大且一致的行为(POSIX规范的一部分).

注意:正如一些评论所指出的那样,这确实更慢但更易于维护,因为它可以适应更复杂的场景,例如,人们想做的不仅仅是一个动作.

解决方案:使用 find

如果你坚持,你可以使用find但实际上不使用xargs,因为它"在读取非NUL分隔的输入时是危险的(破坏,可利用等)":

find . -maxdepth 1 -name '*.pdf' -delete 
Run Code Online (Sandbox Code Playgroud)

使用-maxdepth 1 ... -delete而不是-exec rm {} +允许find简单地执行所需的系统调用而不使用外部进程,因此更快(感谢@chepner注释).

参考

  • 很好的答案,这就是应该回答所有SO问题的方法.谢谢! (28认同)
  • 将其用作*中的f;rm“ $ f”; 完成`作为魅力 (3认同)
  • `find -exec`解决方案似乎比`for`循环快得多. (3认同)
  • 五年之后的4.15.0(确切地说是`4.15.0-1019-gcp`),限制仍然是2097152.有趣的是,在linux git repo上搜索ARG_MAX给出的结果显示[ARG_MAX为131702 ](https://github.com/torvalds/linux/blob/6f0d349d922ba44e4348a17a78ea51b7135965b1/include/uapi/linux/limits.h) (2认同)

Thi*_*ter 178

find有一个-delete动作:

find . -maxdepth 1 -name '*.pdf' -delete
Run Code Online (Sandbox Code Playgroud)

  • 这听起来像是一个臭虫. (7认同)
  • 这仍然会返回"参数列表太长".至少对我来说确实如此.根据丹尼斯的回答,使用`xargs`按预期工作. (4认同)
  • @Sergio有同样的问题,它是由名称模式周围缺少引号引起的. (3认同)
  • @mathreadler 它解决了一个事实,即`-exec` 的一个常见用例是删除一堆文件。`-exec rm {} +` 会做同样的事情,但仍然需要启动至少一个外部进程。`-delete` 允许 `find` 在不使用外部包装器的情况下简单地执行所需的系统调用本身。 (2认同)

por*_*ast 21

另一个答案是强制xargs批量处理命令.例如,一次到delete文件100,cd进入目录并运行:

echo *.pdf | xargs -n 100 rm

  • 为了删除linux中的命令,如果你是一名工程师并输入错误,这可能是一场灾难,我相信它是"最安全的,我知道发生了什么"是最好的.如果你错过键入一个点会让你的公司在一分钟内崩溃,这不是一件好事. (4认同)
  • 请注意,这只适用于“echo”是 shell 内置命令的情况。如果您最终使用命令“echo”,您仍然会遇到程序参数限制。 (2认同)

Dhi*_*mal 20

对于没有时间的人。 在终端上运行以下命令。

ulimit -S -s unlimited
Run Code Online (Sandbox Code Playgroud)

然后执行cp/mv/rm操作。


Jon*_*Lin 13

或者您可以尝试:

find . -name '*.pdf' -exec rm -f {} \;
Run Code Online (Sandbox Code Playgroud)


小智 11

如果您尝试一次删除大量文件(我今天删除了485,000+的目录),您可能会遇到此错误:

/bin/rm: Argument list too long.
Run Code Online (Sandbox Code Playgroud)

问题是当你键入类似的内容时rm -rf *,*会替换为每个匹配文件的列表,例如"rm -rf file1 file2 file3 file4"等等.有一个相对较小的内存缓冲区分配给存储这个参数列表,如果它被填满,shell将不会执行该程序.

为了解决这个问题,很多人会使用find命令查找每个文件并将它们逐个传递给"rm"命令,如下所示:

find . -type f -exec rm -v {} \;
Run Code Online (Sandbox Code Playgroud)

我的问题是我需要删除500,000个文件,这需要花费太长时间.

我偶然发现了一种更快的删除文件的方式 - "find"命令内置了一个"-delete"标志!这是我最终使用的内容:

find . -type f -delete
Run Code Online (Sandbox Code Playgroud)

使用这种方法,我以大约2000个文件/秒的速度删除文件 - 更快!

您还可以在删除文件名时显示这些文件名:

find . -type f -print -delete
Run Code Online (Sandbox Code Playgroud)

...甚至显示将删除多少文件,然后计算删除它们所需的时间:

root@devel# ls -1 | wc -l && time find . -type f -delete
100000
real    0m3.660s
user    0m0.036s
sys     0m0.552s
Run Code Online (Sandbox Code Playgroud)


Big*_*ike 10

你可以试试这个:

for f in *.pdf
do
  rm $f
done
Run Code Online (Sandbox Code Playgroud)

编辑:ThiefMaster评论建议我不要向年轻的shell的jedis透露这种危险的做法,所以我会添加一个更"安全"的版本(为了保存事情,当有人有"-rf .pdf"文件时)

echo "# Whooooo" > /tmp/dummy.sh
for f in '*.pdf'
do
   echo "rm -i $f" >> /tmp/dummy.sh
done
Run Code Online (Sandbox Code Playgroud)

运行上面的内容后,只需打开你的收藏夹中的/tmp/dummy.sh文件即可.编辑并检查每一行的危险文件名,如果找到则将其评论出来.

然后复制工作目录中的dummy.sh脚本并运行它.

所有这些都是出于安全考虑

  • 我认为用一个名为`-rf .. .pdf`的文件可以做很好的事情 (5认同)
  • 这不引用“ $ f”。那就是ThiefMaster所说的。`-rf`优先于`-i`,因此您的第2个版本也不好(未经手动检查)。而且对于提示每个文件,基本上对于批量删除没有用。 (2认同)

小智 6

你可以使用bash数组:

files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
    rm -f "${files[@]:I:1000}"
done
Run Code Online (Sandbox Code Playgroud)

这样,它将逐步擦除1000个文件.

  • 对于大量文件,这似乎要快得多 (2认同)

Fab*_*ath 6

RM命令有哪些可以删除文件同时的限制。

您可以根据文件模式多次使用rm命令删除它们,例如:

rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf
Run Code Online (Sandbox Code Playgroud)

您还可以通过find命令删除它们:

find . -name "*.pdf" -exec rm {} \;
Run Code Online (Sandbox Code Playgroud)

  • 不,`rm` 对它将处理的文件数量没有这样的限制(除了它的 `argc` 不能大于 `INT_MAX`)。这是内核对*整个参数数组*的最大大小的限制(这就是文件名的长度很重要的原因)。 (5认同)

Ale*_*elo 6

如果它们是带有空格或特殊字符的文件名,请使用:

find -name "*.pdf" -delete
Run Code Online (Sandbox Code Playgroud)

仅适用于当前目录中的文件:

find -maxdepth 1 -name '*.pdf' -delete
Run Code Online (Sandbox Code Playgroud)

这句话搜索当前目录(-maxdepth 1)中所有扩展名为pdf(-name '*.pdf')的文件,然后删除。


dps*_*dps 6

我很惊讶这里没有ulimit答案。每次我遇到这个问题时,我都会在这里这里结束。我知道这个解决方案有局限性,但ulimit -s 65536似乎经常对我有用。


Sar*_* Ak 5

你可以用这个表彰

find -name "*.pdf"  -delete
Run Code Online (Sandbox Code Playgroud)