Search code examples
bashshellcommand-linecommandquotations

How can I feed this long line of arguments to an executable?


Arguments file

On args.txt, there are long series of arguments for different call of an executable. Each line contain the arguments for a single call of the executable. One line of args.txt looks like

2 1 -A 7 -B true -C 0.0035 -D /path/to/somewhere ....

The line start by 2 1 as the first two arguments to be given to the executable are "unnamed" (do not come with a flag).

First try

I first tried

i=5
./myexec `sed "${i}q;d" args.txt`

it works most of the time. However, for some lines, the arguments are too long and I receive Error: Command Line Too long as I am overpassing getconf ARG_MAX. Note the software does not allow for specifying arguments other than through the command line.

Second try

So I tried

sed "${i}q;d" args.txt | xargs ./myexec

This second try causes the executable to return nothing.

Questions

  • Am I doing something wrong with sed "${i}q;d" args.txt | xargs ./myexec?
  • Once I fix the second try, will I encounter the same issue (Command Line Too long) as for the first try?
  • Could there be a quotation issue which causes ./myexec to consider the long string as a single argument or something similar?
  • Would you suggest me trying another way of feeding the arguments to myexec?

FYI

I am on Mac OS X 10.11.3 with Terminal 2.6.1


Solution

  • ARG_MAX is an operating-system constraint on the combined size of command-line arguments and environment variables.

    Because it's an operating-system-enforced constraint, you can't bypass it without operating-system-level changes. xargs will split your code into multiple invocations, but each invocation is given only a subset of the arguments desired.

    What you can do then, if you can't decrease the length of your argument list (and the program you're running can't read configuration by any means other than the command line), is unset any environment variables you don't need.


    If you'd rather fail outright when your command-line argument list is too long to correctly execute, rather than (as xargs does) run two or more invocations each with a subset of the arguments given, I would suggest the following code be used for each line:

    args=( )
    while IFS= read -r -d '' arg; do
      args+=( "$arg")
    done < <(xargs printf '%s\0' <<<"$line")
    
    ./yourprog "${args[@]}"