On Fri, 2008-10-17 at 23:52 -0500, Les Mikesell wrote:
Robert Nichols wrote:
These shouldn't make any difference. The limit is on the size of the expanded shell command line.
Really?
$ M=0; N=0; for W in `find /usr -xdev 2>/dev/null`; do M=$(($M+1)); N=$(($N+${#W}+1)); done; echo $M $N 156304 7677373
vs.
$ /bin/echo `find /usr -xdev 2>/dev/null` bash: /bin/echo: Argument list too long
For the first case, the shell never tries to pass the list as command arguments. It builds the list internally, limited only by memory size, and processes the words one by one.
Is that peculiar to bash? I thought the `command` construct was expanded by shells into the command line before being evaluated.
IIRC, none of the above make a "command line". Everything but the
`find /usr -xdev 2>/dev/null`
is a bash "internal command". IIRC, what should happen here is a new instance of bash is spawned as part of a pipeline that sends the output of the find (which is "exec'd" by that new instance of bash, the child) into the parent. The parent reads the input from the pipe and can do whatever it wants, in this case build an array. It then uses the array as data to the loop.
The "command line" is never constructed with the long list. It is only passed to the child (the new instance of bash that is part of the pipeline). That instance receives an argument count and an array of pointers to the arguments. In "C" parlance it looks something like this.
main(argc, *argv[]) /* could be **argv instead */ { /* stuff to do */ . . . }
The "*argv[]" pointers point to the parts of the "command line",
find /usr -xdev
The child execs find, passing the "/usr" and "-xdev" as arguments to find (which has a similar "main" construct), another "command line". The I/O redirection was already done by the parent, so the child need not even know that "stdout" is a pipe.
The longest command line in this case is "find /usr -xdev', 15 characters. Find "sees" only 10 characters.
I hope I've remembered correctly, that this is not FUD, and that it helps someone.
<snip>