Bash 命令行和输入限制
Posted
技术标签:
【中文标题】Bash 命令行和输入限制【英文标题】:Bash command line and input limit 【发布时间】:2013-10-21 16:50:45 【问题描述】:在 bash(或其他 shell)中是否对输入的长度施加了某种字符限制?如果有,字数限制是多少?
即是否可以在 bash 中编写一个太长而无法执行命令行的命令? 如果没有要求的限制,是否有建议的限制?
【问题讨论】:
input 限制与 OS 级别参数 限制有很大不同(请注意,除了参数之外的一些东西,例如环境变量,也适用于那个)。传递给操作系统的生成命令可以比生成它的 shell 命令包含更多或更少的字符。 【参考方案1】:命令行长度的限制不是由 shell 强加的,而是由操作系统强加的。此限制通常在数百 KB 范围内。 POSIX 表示此限制ARG_MAX
,在符合 POSIX 的系统上,您可以使用
$ getconf ARG_MAX # Get argument limit in bytes
例如在 Cygwin 上,这是 32000,而在我使用的不同 BSD 和 Linux 系统上,它是 131072 到 2621440 之间的任何位置。
如果您需要处理超出此限制的文件列表,您可能需要查看xargs
实用程序,该实用程序使用不超过ARG_MAX
的参数子集重复调用程序。
要回答您的具体问题,是的,可以尝试运行参数列表过长的命令。 shell 将出错并显示“参数列表太长”的消息。
请注意,程序的输入(在标准输入或任何其他文件描述符上读取)不受限制(仅受可用程序资源的限制)。因此,如果您的 shell 脚本将一个字符串读入一个变量,那么您将不受ARG_MAX
的限制。该限制也不适用于 shell-builtins。
【讨论】:
@KrzysztofJabłoński 不太可能,因为LONG_VAR
的内容是在标准输入上传递的——这完全是在 shell 中完成的;它没有作为cmd
的参数展开,因此fork()/exec() 的ARG_MAX 限制不起作用。自己尝试很容易:创建一个内容超过 ARG_MAX 的变量并运行您的命令。
这里澄清一下,记录在案:对于一个 8 兆字节的 m4a 文件,我做了:blah="$(cat /home/schwager/Music/Recordings/20090420\ 131623.m4a)"; cat <<< $blah >/dev/null
。注意没有错误。
一点警告。环境变量也很重要。 sysconf manpage > ARG_MAX 很难使用,因为没有指定用户的 > 环境变量消耗了多少 exec(3) 的参数空间。
@user188737 我觉得这是BUGS 的一个很大的警告。例如,macOS 10.12.6 上的 xargs
限制了它尝试放入一个 exec()
到 ARG_MAX - 4096
的数量。所以使用xargs
的脚本可能会起作用,直到有一天有人在环境中放置了太多东西。现在遇到这个问题(解决它:xargs -s ???
)。
@Jens 您的回答是关于fork()/exec()
的限制,而不是关于shell 可以在输入行上处理多少(交互与否)。 – 所以这不是在回答问题。 (我确实看到 shell 的一些命令会调用其他程序,因此参数会在那里传递,但这是另一回事。)【参考方案2】:
好的,居民们。所以我已经接受命令行长度限制作为福音很长一段时间了。那么,如何处理一个人的假设?自然-检查它们。
我有一台 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。
仔细阅读documentation for ARG_MAX
状态,执行函数的最大参数长度。这意味着:不调用exec
,就没有ARG_MAX
限制。所以它可以解释为什么 shell 内置函数不受 ARG_MAX
的限制。
事实上,如果我的参数列表长 109948 个文件,或者大约 2,089,000 个字符(给或取),我可以ls
我的目录。但是,一旦我再添加一个 18 个字符的文件名文件,就会收到 Argument list too long 错误。所以ARG_MAX
正在像宣传的那样工作:执行失败,参数列表中的字符超过ARG_MAX
- 包括,应该注意的是环境数据。
【讨论】:
嗯。我没有阅读现有答案以暗示内置函数受到相关约束,但肯定可以看到有人可以做到。 是的,我认为很难记住——尤其是对于较新的命令行 afficianados——调用内置 bash 与 fork/exec'ing 命令的情况在非显而易见的方式上是不同的。我想澄清这一点。我在工作面试中(作为 Linux 系统管理员)总是会遇到的一个问题是,“所以我在一个目录中有一堆文件。我如何遍历所有这些文件......”提问者总是朝着这条线前进长度限制并想要一个 find/while 或 xargs 解决方案。将来我会说,“啊,地狱——只需使用 for 循环。它可以处理它!” :-) @MikeS 虽然您可以执行 for 循环,但如果您可以使用 find-xargs 组合,您的分叉会少很多并且会更快。 ;-) @LesterCheungfor f in *; do echo $f; done
根本不会分叉(所有内置函数)。所以我不知道 find-xargs 组合会更快;它尚未经过测试。确实,我不知道 OP 的问题集是什么。也许find /path/to/directory
对他没有用,因为它会返回文件的路径名。也许他喜欢for f in *
循环的简单性。无论如何,谈话是关于线路输入限制——而不是效率。因此,让我们继续讨论与命令行长度有关的主题。
FWIW,我记得这个问题只是试图用 C 编写一个 shell,并确定我应该允许输入多长时间。【参考方案3】:
有一个类似 1024 的缓冲区限制。读取只会在粘贴或输入中间挂起。要解决此问题,请使用 -e 选项。
http://linuxcommand.org/lc3_man_pages/readh.html
-e 使用 Readline 获取交互式 shell 中的行
将您的阅读更改为阅读 -e 并且烦人的行输入挂起消失。
【讨论】:
这与read
无关:“即,是否可以在 bash 中编写一个太长而无法执行命令行的命令?”
@ChaiT.Rex 你说的有点对,但事情是这样的:尝试在没有 Readline 的情况下以交互方式运行 Bash,即 bash --noediting
,并在新提示符下尝试运行命令 echo somereallylongword
,其中somereallylongword 超过 4090 个字符。在 Ubuntu 18.04 上试过,这个词被截断了,所以显然它确实与未启用 Readline 有关。
@Amir 有趣!你是对的!我试图编辑答案,但后来我意识到 -e 选项在这种情况下不适用于 bash(在 bash 中,它会在出错时立即退出 shell)。我不确定保罗为什么转而阅读。无论如何,当使用 --noreadline 启动 bash 时,缓冲区限制在 4-5000 个字符之间。这是我不知道或没有预料到的副作用。
赞成,因为阅读是我在房间里追逐的问题孩子,这个答案让我到了正确的地方。谢谢!以上是关于Bash 命令行和输入限制的主要内容,如果未能解决你的问题,请参考以下文章