Linux命令中的“参数列表过长”错误
概述
在本文中,我们将讨论在您尝试在 Linux 系统上执行命令时显示的错误消息,该消息显示为“参数列表过长”。此错误可能由多种原因造成。在本篇文章中,我将解释导致此错误的原因以及如何解决它。
什么是“参数列表过长”错误?
此错误是由于向程序或 shell 脚本传递了无效的参数而发生的。这意味着程序允许的参数数量超过了限制。例如,如果您运行以下命令:
ls -l /usr/bin/* | grep binutils
您可能会收到以下错误:
-bash: /usr/bin/grep: Argument list too long
如果您想知道上述命令失败的原因,请继续阅读。
导致错误的原因是什么?
我们将研究一个目录中有很多文件的情况。
$ ls -lrt | wc -l 230086 $ ls -lrt | tail -5 -rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120038.log -rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120040.log -rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120039.log -rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120042.log -rw-r--r-- 1 shubh shubh 0 Nov 30 14:02 events2120041.log
我们的文件夹中有超过 230K 个日志文件名。让我们看看我们能否获得以单词“events”开头的文件数量。
$ ls -lrt events* | wc -l -bash: /usr/bin/ls: Argument list too long 0
值得注意的是,命令失败,并以“参数列表过长”为由。让我们尝试使用 rm 命令来删除这些文件:
$ rm -rf events*.log -bash: /usr/bin/rm: Argument list too long
该命令再次因为同样的原因失败。
在执行文件名扩展时,Bash 执行一个称为“扩展”的操作,这意味着它将 * 字符与每个匹配的文件名扩展。结果,Bash 创建了一个非常长的参数字符串,它无法处理。
如果作为命令行参数扩展的文件过多,Bash 可能无法处理它们。请注意,此缓冲区(参数缓冲区)与环境变量信息共享,因此实际可用内存小于此缓冲区。
之前的示例中的 rmdir(删除目录)命令扩展为:
$ rm -rf events2120038.log events2120040.log ... events0000001.log
这里,参数向量变得比文件中的行数更多。为避免参数过多,我们使用 getcwd() 函数获取当前工作目录(从文件系统根目录到我们当前位置的路径)。然后,我们使用 getargs() 函数从文件的每一行提取第一个参数。最后,我们使用 strlen() 函数确定结果字符串的长度。
$ getconf ARG_MAX 2097152
ARG_max 参数确定 exec() 函数所需的最大空间。它允许内核知道执行程序所需的最大缓冲区。您可以使用 xargs 命令验证这些限制。
$ xargs --show-limits Your environment variables take up 2504 bytes POSIX upper limit on argument length (this system): 2092600 POSIX smallest allowable upper limit on argument length (all systems): 4096 Maximum length of command we could actually use: 2090096 Size of command buffer we are actually using: 131072 Maximum parallelism (--max-procs must be no greater): 2147483647
关于参数长度上限最重要的一点是,它们在不同的操作系统之间可能有所不同。
克服限制
我们将研究解决此问题的不同方法。所有这些方法都涉及避免参数扩展。
使用find命令
您可以使用 find 命令迭代文件名,并使用 exec 选项或 xargs 命令逐个执行它们。
$ find . -iname "events*" | xargs ls -lrt | wc -l 230085
我们首先使用 find 命令获取包含字符串“events”的文件名。接下来,我们将 find 命令的输出传递给 xargs 命令。最后,我们对 xargs 命令的结果运行 ls 和 wc 命令。
使用for循环方法
您可以使用另一种方法通过 for 循环迭代文件。
$ for f in events*; do echo "$f"; done | wc -l 230085
这是解决此问题的几个简单解决方案之一。它可能比其他方法花费更长时间,但它效果很好。
手动分割
我们可以将文件分割成更小的块,并使用不同的字符串集作为参数在每次迭代中重复运行命令。
$ ls -lrt events1*.log | wc -l 31154 $ ls -lrt events2*.log | wc -l 15941
我们只过滤名称以“events1”开头的文件。在这种特定情况下,我们保持在 ARG_MAX 变量设置的限制范围内。
然后,我们对以“event1”、“event2”等开头的文件重复相同的步骤。
当我们只需要删除目录的内容时
如果我们尝试从目录中删除所有文件,那么考虑一下我们无法做到这一点的情况:
$ rm -rf * -bash: /usr/bin/rm: Argument list too long
如果我们想解决这个问题,我们可以改为删除目录并重新创建它。
$ rm -rf /home/shubh/tempdir/logs_archive $ cd home/shubh/tempdir && mkdir logs_archive
这里,logs_archive 文件夹包含我们要删除的文件。
由于我们正在删除文件夹并重新创建它,因此这种方法不会保留文件夹的原始权限设置或所有权。
结论
我们研究了几种处理“过长”问题的方法。
我们首先讨论了导致此问题的原因,然后研究了一些解决方法。