当我运行类似的命令时ls */*/*/*/*.jpg
,我收到错误
-bash: /bin/ls: Argument list too long
我知道为什么会发生这种情况:这是因为命令参数的空间量存在内核限制。标准建议是更改我使用的命令,以避免需要太多的参数空间(例如, usefind
和xargs
)。
如果我不想更改命令怎么办?如果我想继续使用相同的命令怎么办?我怎样才能让事情“正常工作”,而不会出现此错误?有哪些可用的解决方案?
答案1
在 Linux 上,命令参数的最大空间量是可用堆栈空间量的 1/4。因此,解决方案是增加堆栈的可用空间量。
简短版本:运行类似的东西
ulimit -s 65536
较长版本:堆栈的默认可用空间量约为 8192 KB。您可以看到可用空间量,如下所示:
$ ulimit -s
8192
选择一个较大的数字,并设置堆栈的可用空间量。例如,如果您想尝试允许堆栈最多 65536 KB,请运行以下命令:
$ ulimit -s 65536
您可能需要通过反复试验来确定需要多大的大小。在许多情况下,这是一个快速而肮脏的解决方案,它将消除修改命令和计算 、 等语法的需要find
(xargs
尽管我意识到这样做还有其他好处)。
我相信这是 Linux 特有的。我怀疑它可能对任何其他 Unix 操作系统没有帮助(未经测试)。
答案2
而不是ls */*/*/*/*.jpg
,请尝试:
echo */*/*/*/*.jpg | xargs ls
xargs
(1) 知道系统上参数的最大数量是多少,并且将分解其标准输入以多次调用指定的命令行,并且参数不超过该限制,无论它是什么(您也可以将其设置为更低比使用该选项的操作系统的最大值-n
)。
例如,假设限制为 3 个参数,并且您有 5 个文件。在这种情况下xargs
将执行ls
两次:
ls 1.jpg 2.jpg 3.jpg
ls 4.jpg 5.jpg
通常这是完全合适的,但并非总是如此 - 例如,您不能依赖ls
(1)排序正确地为您排序所有条目,因为每个单独的ls
- 调用只会对 给定的条目子集进行排序xargs
。
尽管您可以按照其他人的建议提高限制,但限制仍然存在 - 有一天您的 JPG 收藏将再次超出它。你应该准备你的脚本来处理无限数量的......
答案3
这Linux 期刊文章给出4个解决方案。只有第四种解决方案不涉及更改命令:
方法 #4 涉及手动增加内核中为命令行参数分配的页数。如果您查看 include/linux/binfmts.h 文件,您会在顶部附近发现以下内容:
/* * MAX_ARG_PAGES defines the number of pages allocated for arguments * and envelope for the new program. 32 should suffice, this gives * a maximum env+arg of 128kB w/4KB pages! */ #define MAX_ARG_PAGES 32
为了增加专用于命令行参数的内存量,您只需提供更大的 MAX_ARG_PAGES 值即可。保存此编辑后,只需像平常一样重新编译、安装并重新启动到新内核即可。
在我自己的测试系统上,我通过将该值提高到 64 成功解决了所有问题。经过大量测试,自从切换以来我没有遇到任何问题。这完全是预料之中的,因为即使
MAX_ARG_PAGES
设置为 64,我可以生成的最长的命令行也只会占用 256KB 的系统内存——按照当今的系统硬件标准来说,这并不算多。方法#4 的优点很明显。您现在可以像平常一样简单地运行该命令,并且它会成功完成。缺点同样明显。如果将命令行可用的内存量增加到超出可用系统内存量,则可能会对您自己的系统发起 DOS 攻击并导致系统崩溃。特别是在多用户系统上,即使很小的增加也会产生重大影响,因为每个用户都会分配额外的内存。因此,请始终在您自己的环境中进行广泛的测试,因为这是确定方法 #4 是否适合您的最安全的方法。
我同意这个限制非常烦人。
答案4
如果达到池空间限制,Bash 系统调用及其直接变体(参数和环境变量)将产生“参数列表太长”。
我发现如何避免这个限制,在处理特殊字符在文件名(例如空格)中,使用打印函数和参数:
printf '%s\0' */*/*/*/*.jpg | xargs -0 ls