Linux命令中的“参数列表太长”错误
1.概述
在本教程中,我们将研究**处理大量文件时经常遇到的“参数列表太长”问题。**首先,我们将讨论导致它的原因。然后,我们将讨论一些有助于我们解决此问题的解决方案。
2. 什么原因导致错误
让我们考虑一个目录中存在大量文件的情况:
$ ls -lrt | wc -l
230086
$ ls -lrt | tail -5
-rw-r--r-- 1 shubh shubh 0 Apr 30 14:02 events2120038.log
-rw-r--r-- 1 shubh shubh 0 Apr 30 14:02 events2120040.log
-rw-r--r-- 1 shubh shubh 0 Apr 30 14:02 events2120039.log
-rw-r--r-- 1 shubh shubh 0 Apr 30 14:02 events2120042.log
-rw-r--r-- 1 shubh shubh 0 Apr 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 无法处理它。**请注意,此缓冲区与环境空间信息共享,因此实际可用空间小于此缓冲区大小。
上一个示例中的rm命令扩展为:
$ rm -rf events2120038.log events2120040.log ... events0000001.log
在这里,参数列表变得等于目录中的文件数。在我们的例子中,这是超过230K的文件,这引起了很多争论。我们可以利用getconf命令获取当前系统限制:
$ 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
*这里最感兴趣的信息是“参数长度的上限”*,**它可能因系统而异。
3. 克服局限
让我们深入研究可以用来解决这个问题的各种方法。所有提出的解决方案的共同点是它们避免了参数扩展。
3.1. 使用查找命令
**我们可以使用find 命令迭代文件列表,**然后使用exec 选项或xargs命令:
$ find . -iname "events*" | xargs ls -lrt | wc -l
230085
首先,我们使用find命令获取以单词*“events”开头的所有文件的列表。然后,我们使用xargs命令接受来自标准输入的文件列表,最后,我们对xargs提供的文件列表执行ls和wc*命令。
3.2. 使用for循环方法
另一种有趣的方法是使用for 循环对文件进行迭代:
$ for f in events*; do echo "$f"; done | wc -l
230085
这是解决问题的最简单的技术之一。请注意,此解决方案可能会慢一些。
3.3. 手动拆分
我们可以将文件拆分成更小的文件组,并以不同的字符串集作为参数重复执行命令(例如rm、cp、mv、wc、ls):
$ ls -lrt events1*.log | wc -l
31154
$ ls -lrt events2*.log | wc -l
15941
在这里,我们只过滤以“ events1 ”开头的文件名。在此特定示例中,我们保持在由ARG_MAX值控制的空间要求内。 然后,我们对以“ events2 ”开头的那些做同样的事情,依此类推。
3.4. 当我们只需要删除目录的内容时
考虑这样一种情况,我们试图删除目录中的所有文件,但它失败了:
$ 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目录包含我们要删除的文件。
请注意,由于我们要删除目录并再次创建它,因此这种方法不会保留目录的原始权限或所有权。