ls 的参数列表太长

65 ls arguments

尝试访问ls *.txt | wc -l包含许多文件的目录时出现以下错误:

-bash: /bin/ls: Argument list too long
Run Code Online (Sandbox Code Playgroud)

此“参数列表”的阈值是否取决于发行版或计算机的规格?通常,我wc -l会将如此大的结果的结果通过管道传递给其他一些命令(例如),所以我不关心终端的限制。

Cor*_*ren 68

您的错误消息参数列表太长来自ls *.txt.

这个限制对二进制程序和你的内核都是安全的。有关新进程的更多信息以及如何使用和计算请参阅ARG_MAX,新进程的最大参数长度

管道尺寸没有这样的限制。所以你可以简单地发出这个命令:

find -type f -name '*.txt'  | wc -l
Run Code Online (Sandbox Code Playgroud)

注意:在现代 Linux 上,文件名中的奇怪字符(如换行符)将使用ls或 之类的工具进行转义find,但仍会从 ***** 显示。如果您使用的是旧 Unix,则需要此命令

find -type f -name '*.txt' -exec echo \;  | wc -l
Run Code Online (Sandbox Code Playgroud)

NB2:我想知道如何创建名称中带有换行符的文件。一旦你知道了诀窍,这并不难:

touch "hello
world"
Run Code Online (Sandbox Code Playgroud)

  • @Coren @Mikel - 不是每个人都有 GNU 的“find”。OS X 和基于 busybox 的系统上的“find”,我猜任何基于 BSD 的系统都会显示带有换行符的文件名,这会扰乱计数。 (2认同)

Mik*_*kel 13

这主要取决于您的 Linux 内核版本。

您应该能够通过运行来查看系统的限制

getconf ARG_MAX
Run Code Online (Sandbox Code Playgroud)

它告诉您命令行在被 shell 扩展后可以拥有的最大字节数。

在 Linux < 2.6.23 中,限制通常为 128 KB。

在 Linux >= 2.6.25 中,限制为 128 KB 或堆栈大小的 1/4(请参阅ulimit -s参考资料),以较大者为准。

有关所有详细信息,请参阅execve(2) 手册页


不幸的是,管道ls *.txt不能解决问题,因为限制在于操作系统,而不是外壳。

外壳展开*.txt,然后尝试调用

exec("ls", "a.txt", "b.txt", ...)
Run Code Online (Sandbox Code Playgroud)

并且您有太多匹配的文件*.txt,以至于超出了 128 KB 的限制。

你必须做类似的事情

find . -maxdepth 1 -name "*.txt" | wc -l
Run Code Online (Sandbox Code Playgroud)

反而。

(请参阅下面关于包含换行符的文件名的 Shawn J. Goff 的评论。)

  • @GuilhermeSalomé `.` 表示当前目录,`-maxdepth 1` 表示它不在子目录中查找。这是为了匹配与`*.txt` 相同的文件。 (2认同)

Kei*_*son 10

另一种解决方法:

ls | grep -c '\.txt$'
Run Code Online (Sandbox Code Playgroud)

即使ls产生的输出比ls *.txt产生的(或试图产生的)多,它也不会遇到“参数太长”的问题,因为你没有将任何参数传递给ls. 请注意,grep它采用正则表达式而不是文件匹配模式。

您可能想要使用:

ls -U | grep -c '\.txt$'
Run Code Online (Sandbox Code Playgroud)

(假设您的版本ls支持此选项)。这告诉ls不要对其输出进行排序,这可以节省时间和内存——在这种情况下,顺序无关紧要,因为您只是在计算文件。对输出进行排序所花费的资源通常并不重要,但在这种情况下,我们已经知道您有大量*.txt文件。

并且您应该考虑重新组织您的文件,以便在一个目录中不会有这么多文件。这可能可行,也可能不可行。