Bash命令行和输入限制


90

在bash(或其他shell)中是否存在某种字符限制,以便可以输入多长时间?如果是这样,那个字符限制是多少?

即是否有可能在bash中编写命令而导致命令执行时间太长?如果没有要求的限制,是否有建议的限制?


2
输入限制是非常不同的操作系统级别的参数限制(注意:不是参数,如环境变量的其他一些东西,也适用于对那一个)。传递给操作系统的生成命令比生成它的shell命令可以包含更多或更少的字符。
查尔斯·达菲

Answers:


125

命令行长度的限制不是由外壳施加的,而是由操作系统施加的。此限制通常在数百千字节的范围内。POSIX表示此限制ARG_MAX,在符合POSIX的系统上,您可以使用

$ getconf ARG_MAX    # Get argument limit in bytes

例如在Cygwin上是32000,在不同的BSD和Linux系统上,我使用的是131072到2621440。

如果您需要处理超出此限制的文件列表,则可能需要查看该xargs实用程序,该实用程序以不超过的参数子集重复调用程序ARG_MAX

要回答您的特定问题,是的,有可能尝试在参数列表过长的情况下运行命令。外壳程序将出现错误,并显示“参数列表过长”消息。

注意,输入到一个程序(如读取标准输入或任何其他文件描述符)是受限(仅受可用程序资源)。因此,如果您的Shell脚本将字符串读入变量中,那么您就不会受到限制ARG_MAX。该限制也不适用于shell-builtins。


好的答案,但我想澄清一下。如果我有一个构造cmd <<< "$LONG_VAR"并且LONG_VAR值超出了限制,这会打击我的命令吗?
KrzysztofJabłoński

1
@KrzysztofJabłoński不太可能,因为的内容LONG_VAR是在stdin上传递的,而这完全是在shell中完成的;它不会扩展为的参数cmd,因此fork()/ exec()的ARG_MAX限制不会起作用。尝试一下很容易:创建一个内容超出ARG_MAX的变量并运行命令。
詹斯(Jens)2015年

2
作为记录,这里是澄清:对于一个8兆字节的m4a文件,我做了:blah="$(cat /home/schwager/Music/Recordings/20090420\ 131623.m4a)"; cat <<< $blah >/dev/null。注意没有错误。
Mike S

3
一点警告。环境变量也很重要。 sysconf手册 >很难使用ARG_MAX,因为未指定用户的环境变量消耗了exec(3)的参数空间>。
Gerrit

3
@ user188737我觉得这在BUGS中是一个很大的警告。例如xargs它会尝试多少放在一个MACOS 10.12.6限制exec()ARG_MAX - 4096。因此使用脚本xargs可能会起作用,直到有一天有人将过多的东西放到环境中为止。立即运行(使用:解决该问题xargs -s ???)。
Neuromer

44

好的,居民。因此,我已经接受命令行长度限制作为福音已有一段时间了。那么,如何处理一个人的假设呢?自然地-检查它们。

我可以使用一台Fedora 22机器(意思是:带有bash4的Linux)。我创建了一个包含500,000个inode(文件)的目录,每个目录长18个字符。命令行长度为9,500,000个字符。这样创建:

seq 1 500000 | while read digit; do
    touch $(printf "abigfilename%06d\n" $digit);
done

我们注意到:

$ getconf ARG_MAX
2097152

请注意,但是我可以这样做:

$ echo * > /dev/null

但这失败了:

$ /bin/echo * > /dev/null
bash: /bin/echo: Argument list too long

我可以运行一个for循环:

$ for f in *; do :; done

这是另一个内置的shell。

仔细阅读有关状态的文档,ARG_MAXexec函数的最大参数长度。这意味着:没有调用exec,就没有ARG_MAX限制。因此它可以解释为什么shell内置函数不受的限制ARG_MAX

的确,ls如果我的参数列表长109948个文件或大约208.9万个字符(给定或接受),则可以进入目录。但是,一旦我又添加了一个18个字符的文件名文件,我就会收到一个“参数列表太长”错误。因此ARG_MAX,正如广告所宣传的那样:exec失败,ARG_MAX参数列表上的字符超过了-包括,应该注意的是,环境数据。


嗯 我没有读过现有的答案来暗示内建函数受有关约束的约束,但可以肯定有人会这样做。
查尔斯·达菲

6
是的,我认为很难记住,尤其是对于较新的命令行用户而言,在非显而易见的方式中,调用bash内置命令与fork / exec命令的情况有所不同。我想说清楚。我一直在求职面试中(作为Linux Sysadmin)遇到的一个问题是:“所以我在目录中有一堆文件。我如何遍历所有这些文件……”发问者总是朝着那条直线前进长度限制,并需要一个find / while或xargs解决方案。将来我会说,“啊,该死了,只需要使用for循环即可。它可以处理它!” :-)
Mike S

@MikeS,虽然可以执行for循环,但是如果可以使用find-xargs组合,则可以减少很多派生,并且速度更快。;-)
Lester Cheung

4
@LesterCheungfor f in *; do echo $f; done根本不会分叉(所有内置函数)。所以我不知道find-xargs组合会更快。尚未经过测试。确实,我不知道OP的问题是什么。也许find /path/to/directory对他没有用,因为它将返回文件的路径名。也许他喜欢for f in *循环的简单性。无论如何,讨论的是线路输入限制而不是效率。因此,让我们继续讨论与命令行长度有关的主题。
Mike S

我记得FWIW的问题只是试图用C编写一个shell,并确定允许输入多长时间。
德里克·哈尔登

-3

缓冲区限制大约为1024。读取将只是挂在中间粘贴或输入。要解决此问题,请使用-e选项。

http://linuxcommand.org/lc3_man_pages/readh.html

-e使用Readline在交互式shell中获取行

将读取更改为读取-e,然后烦人的行输入挂起消失。


1
这不是关于read:“是否可以在bash中编写命令,而该命令对于命令行执行时间过长?”
Chai T. Rex

@ ChaiT.Rex您是正确的,但事情是这样的:尝试以不带Readline的方式交互式运行Bash,即bash --noediting,并在新提示下尝试运行命令echo somereallylongword,其中somereallylongword长度超过4090个字符。在Ubuntu 18.04上尝试过,该词被截断了,因此很明显,这与未启用Readline有关。
阿米尔

@Amir有趣!你是对的!我试图编辑答案,但是后来我意识到-e选项不适用于这种情况下的bash(在bash中,它会在出错时立即退出shell)。我不确定保罗为什么要转而读书。无论如何,以--noreadline开始bash时,缓冲区限制为4-5000个字符。这是我不知道或没有想到的副作用。
Mike S
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.