bash 传递带引号的参数时,为什么会出现“/bin/sh: Argument list too long”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11475221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:25:42  来源:igfitidea点击:

Why do I get "/bin/sh: Argument list too long" when passing quoted arguments?

bashshellcommand-lineargumentsquoting

提问by Igor Chubin

How long can be a command line that can be passed to sh -c ''? (in bash and in bourne shell)

可以传递给的命令行有多长时间sh -c ''?(在 bash 和 bourne shell 中)

The limit is much lower than that from the OS (in case of modern Linux).

该限制远低于操作系统的限制(在现代 Linux 的情况下)。

For example:

例如:

$ /bin/true $(seq 1 100000)
$ /bin/sh -c "/bin/true $(seq 1 100000)"
bash: /bin/sh: Argument list too long

And how could I circumvent this problem?

我怎样才能规避这个问题?

Update

更新

I want to note that getconfcan't help here (because that is not a system limit):

我想指出这getconf在这里无济于事(因为这不是系统限制):

$ seq 1 100000 | wc -c
588895
$ getconf ARG_MAX
2097152

Update #2

更新 #2

Now I've understood what is the point here. That is not a shell limit, that is a system limit but for the length of each argument, not for the entire arglist.

现在我明白了这里的意义。这不是 shell 限制,而是系统限制,而是针对每个参数的长度,而不是针对整个 arglist。

$ /bin/true $(seq 1 100000)
$ /bin/true "$(seq 1 100000)"
bash: /bin/true: Argument list too long

Thank you, CodeGnome, for the explanation.

谢谢 CodeGnome 的解释。

采纳答案by Todd A. Jacobs

TL;DR

TL; 博士

A single argument must be shorter than MAX_ARG_STRLEN.

单个参数必须短于 MAX_ARG_STRLEN。

Analysis

分析

According to this link:

根据此链接

And as additional limit since 2.6.23, one argument must not be longer than MAX_ARG_STRLEN (131072). This might become relevant if you generate a long call like "sh -c 'generated with long arguments'".

作为 2.6.23 以来的额外限制,一个参数不得长于 MAX_ARG_STRLEN (131072)。如果您生成像“sh -c 'generated with long arguments'”这样的长调用,这可能会变得相关。

This is exactly the "problem" identified by the OP. While the number of arguments allowed may be quite large (see getconf ARG_MAX), when you pass a quoted command to /bin/shthe shell interprets the quoted command as a single string. In the OP's example, it is this single string that exceeds the MAX_ARG_STRLEN limit, not the length of the expanded argument list.

这正是 OP 确定的“问题”。虽然允许的参数数量可能非常大(请参阅 参考资料getconf ARG_MAX),但当您将带引号的命令传递给/bin/sh 时,shell 会将带引号的命令解释为单个字符串。在 OP 的示例中,正是这个单个字符串超出了 MAX_ARG_STRLEN 限制,而不是扩展参数列表的长度。

Implementation Specific

具体实现

Argument limits are implementation specific. However, this Linux Journal articlesuggests several ways to work around them, including increasing system limits. This may not be directly applicable to the OP, but it nonetheless useful in the general case.

参数限制是特定于实现的。但是,这篇 Linux Journal 文章提出了几种解决方法,包括增加系统限制。这可能不直接适用于 OP,但它在一般情况下仍然有用。

Do Something Else

做点别的

The OP's issue isn't actually a real problem. The question is imposing an arbitrary constraint that doesn't solve a real-world problem.

OP的问题实际上并不是真正的问题。问题是强加了一个不能解决现实世界问题的任意约束。

You can work around this easily enough by using loops. For example, with Bash 4:

您可以通过使用循环轻松解决此问题。例如,使用 Bash 4:

for i in {1..100000}; do /bin/sh -c "/bin/true $i"; done

works just fine. It will certainly be slow, since you're spawning a process on each pass through the loop, but it certainly gets around the command-line limit you're experiencing.

工作得很好。它肯定会很慢,因为您在每次通过循环时都会生成一个进程,但它肯定会绕过您遇到的命令行限制。

Describe Your Real Problem

描述你真正的问题

If a loop doesn't resolve your issue, please update the question to describe the problem you're actually trying to solve using really long argument lists. Exploring arbitrary line-length limits is an academic exercise, and not on-topic for Stack Overflow.

如果循环不能解决您的问题,请更新问题以使用非常长的参数列表来描述您实际尝试解决的问题。探索任意行长度限制是一项学术练习,而不是 Stack Overflow 的主题。

回答by Paused until further notice.

I don't get that error message. My secret? Single quotes:

我没有收到那个错误信息。我的秘密?单引号:

/bin/sh -c '/bin/true $(seq 1 100000)'

If I use double quotes, I get that error with every shell:

如果我使用双引号,则每个 shell 都会出现该错误:

$ /bin/sh -c "/bin/true $(seq 1 100000)"
-bash: /bin/sh: Argument list too long
$ /bin/bash -c "/bin/true $(seq 1 100000)"
-bash: /bin/bash: Argument list too long
$ /bin/ksh -c "/bin/true $(seq 1 100000)"
-bash: /bin/ksh: Argument list too long
$ /bin/zsh -c "/bin/true $(seq 1 100000)"
-bash: /bin/zsh: Argument list too long

The argument list gets expanded in the current shell when double quotes are used as evidenced by the fact that Bash is the one issuing the error "-bash: ..." regardless of the shell being used to run the command. On my system shis Dash, by the way.

当使用双引号时,参数列表在当前 shell 中得到扩展,事实证明,Bash 是发出错误“-bash: ...”的那个,而不管用于运行命令的 shell。sh顺便说一下,在我的系统上是 Dash。

This holds true even for other "host" shells:

即使对于其他“主机”外壳也是如此:

$ dash
$ /bin/bash -c '/bin/true $(seq 1 100000)'
$ /bin/bash -c "/bin/true $(seq 1 100000)"
dash: /bin/bash: Argument list too long

Patient: Doctor, it hurts when I do this."
Doctor: Don't do that.

病人:医生,我这样做会痛。”
医生:不要那样做。

回答by Nahuel Fouilleul

on my os it's the max length obtained by dichotomy

在我的操作系统上,它是通过二分法获得的最大长度

/bin/sh -c "/bin/true $(perl -e 'print"a"x131061')"

so it gives 131071

所以它给出了 131071

but there is no reason to have a line as long ; if it's due to a large number of arguments, "$@" can be used instead; for example

但没有理由排那么长;如果是由于参数较多,可以用“$@”代替;例如

/bin/sh -c 'command "$@"' -- arg1 arg2 .. argn

回答by dannysauer

Make a file with #!/bin/shas the first line, then the put rest of your command on subsequent lines? :)

创建一个文件#!/bin/sh作为第一行,然后将命令的其余部分放在后续行中?:)

More seriously, you can also read commands from STDIN using the -soption, so you can generate your long command line and pipe it in to /bin/sh -s

更严重的是,您还可以使用该-s选项从 STDIN 读取命令,因此您可以生成长命令行并将其通过管道传输到/bin/sh -s