Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

The limit is much lower than that from the OS (in case of modern 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 getconf can't help here (because that is not a system limit):

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

Update #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.

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

Thank you, CodeGnome, for the explanation.

like image 482
Igor Chubin Avatar asked Jul 13 '12 17:07

Igor Chubin


People also ask

How do I fix an argument that is too long?

The Solution There are several solutions to this problem (bash: /usr/bin/rm: Argument list too long). Remove the folder itself, then recreate it. If you still need that directory, then recreate it with the mkdir command.

How do you determine the number of arguments passed to the script?

You can get the number of arguments from the special parameter $# . Value of 0 means "no arguments". $# is read-only. When used in conjunction with shift for argument processing, the special parameter $# is decremented each time Bash Builtin shift is executed.

How do I pass multiple arguments to a shell script?

To pass multiple arguments to a shell script you simply add them to the command line: # somescript arg1 arg2 arg3 arg4 arg5 … To pass multiple arguments to a shell script you simply add them to the command line: # somescript arg1 arg2 arg3 arg4 arg5 …


1 Answers

TL;DR

A single argument must be shorter than 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'".

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/sh the 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.

Implementation Specific

Argument limits are implementation specific. However, this Linux Journal article suggests 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.

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.

You can work around this easily enough by using loops. For example, with 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.

like image 77
Todd A. Jacobs Avatar answered Sep 28 '22 05:09

Todd A. Jacobs