“参数列表太长”:在不更改命令的情况下如何处理它?

“参数列表太长”:在不更改命令的情况下如何处理它?

当我运行类似的命令时ls */*/*/*/*.jpg,我收到错误

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

我知道为什么会发生这种情况:这是因为命令参数的空间量存在内核限制。标准建议是更改我使用的命令,以避免需要太多的参数空间(例如, usefindxargs)。

如果我不想更改命令怎么办?如果我想继续使用相同的命令怎么办?我怎样才能让事情“正常工作”,而不会出现此错误?有哪些可用的解决方案?

答案1

在 Linux 上,命令参数的最大空间量是可用堆栈空间量的 1/4。因此,解决方案是增加堆栈的可用空间量。

简短版本:运行类似的东西

ulimit -s 65536

较长版本:堆栈的默认可用空间量约为 8192 KB。您可以看到可用空间量,如下所示:

$ ulimit -s
8192

选择一个较大的数字,并设置堆栈的可用空间量。例如,如果您想尝试允许堆栈最多 65536 KB,请运行以下命令:

$ ulimit -s 65536

您可能需要通过反复试验来确定需要多大的大小。在许多情况下,这是一个快速而肮脏的解决方案,它将消除修改命令和计算 、 等语法的需要findxargs尽管我意识到这样做还有其他好处)。

我相信这是 Linux 特有的。我怀疑它可能对任何其他 Unix 操作系统没有帮助(未经测试)。

答案2

而不是ls */*/*/*/*.jpg,请尝试:

echo */*/*/*/*.jpg | xargs ls

xargs(1) 知道系统上参数的最大数量是多少,并且将分解其标准输入以多次调用指定的命令行,并且参数不超过该限制,无论它是什么(您也可以将其设置为更低比使用该选项的操作系统的最大值-n)。

例如,假设限制为 3 个参数,并且您有 5 个文件。在这种情况下xargs将执行ls两次:

  1. ls 1.jpg 2.jpg 3.jpg
  2. 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

相关内容