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 文件夹包含我们要删除的文件。

由于我们正在删除文件夹并重新创建它,因此这种方法不会保留文件夹的原始权限设置或所有权。

结论

我们研究了几种处理“过长”问题的方法。

我们首先讨论了导致此问题的原因,然后研究了一些解决方法。

更新于:2022年12月26日

2K+ 次查看

启动您的职业生涯

通过完成课程获得认证

开始
广告