Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BASH shell expand arguments with spaces from variable [duplicate]

Say I have a variable $ARGS which contains the following:

file1.txt "second file.txt" file3.txt

How can I pass the contents of $ARGS as arguments to a command (say cat $ARGS, for example), treating "second file.txt" as one argument and not splitting it into "second and file.txt"?

Ideally, I'd like to be able to pass arguments to any command exactly as they are stored in a variable (read from a text file, but I don't think that's pertinent).

Thanks!

like image 914
Stephen Humphries Avatar asked Sep 20 '16 04:09

Stephen Humphries


People also ask

How do you pass arguments with spaces to a shell script?

Arguments can be passed to the script when it is executed, by writing them as a space-delimited list following the script file name. Inside the script, the $1 variable references the first argument in the command line, $2 the second argument and so forth. The variable $0 references to the current script.

What is the difference between $@ and $* in bash?

There is no difference if you do not put $* or $@ in quotes. But if you put them inside quotes (which you should, as a general good practice), then $@ will pass your parameters as separate parameters, whereas $* will just pass all params as a single parameter.

What does $() mean in bash?

Example of command substitution using $() in Linux: Again, $() is a command substitution which means that it “reassigns the output of a command or even multiple commands; it literally plugs the command output into another context” (Source).

What does $@ do bash?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.


1 Answers

It's possible to do this without either bash arrays or eval: This is one of the few places where the behavior of xargs without either -0 or -d extensions (a behavior which mostly creates bugs) is actually useful.

# this will print each argument on a different line
# ...note that it breaks with arguments containing literal newlines!
xargs printf '%s\n' <<<"$ARGS"

...or...

# this will emit arguments in a NUL-delimited stream
xargs printf '%s\0' <<<"$ARGS"

# in bash 4.4, you can read this into an array like so:
readarray -t -d '' args < <(xargs printf '%s\0' <<<"$ARGS")
yourprog "${args[@]}" # actually run your programs

# in bash 3.x or newer, it's just a bit longer:
args=( );
while IFS= read -r -d '' arg; do
    args+=( "$arg" )
done < <(xargs printf '%s\0' <<<"$ARGS")
yourprog "${args[@]}" # actually run your program

# in POSIX sh, you can't safely handle arguments with literal newlines
# ...but, barring that, can do it like this:
set --
while IFS= read -r arg; do
    set -- "$@" "$arg"
done < <(printf '%s\n' "$ARGS" | xargs printf '%s\n')
yourprog "$@" # actually run your program

...or, letting xargs itself do the invocation:

# this will call yourprog with ARGS given
# ...but -- beware! -- will cause bugs if there are more arguments than will fit on one
# ...command line invocation.
printf '%s\n' "$ARGS" | xargs yourprog
like image 69
Charles Duffy Avatar answered Sep 19 '22 14:09

Charles Duffy