I Would Like to Store All Command-Line Arguments to a Bash Script into a Single Variable

I would like to store all command-line arguments to a Bash script into a single variable

echo "$*"

would do what you want, namely printing out the entire command-line arguments, separated by a space (or, technically, whatever the value of $IFS is). If you wanted to store it into a variable, you could do

thevar="$*"

If that doesn't answer your question well enough, I'm not sure what else to say...

BASH store command line arguments as separate variables

They already are stored in a variable: $@. You can access the individual indices as $1, $2, etc. You don't need to store them in new variables if those are sufficient.

# Loop over arguments.
for arg in "$@"; do
echo "$arg"
done

# Access arguments by index.
echo "First = $1"
echo "Second = $2"
echo "Third = $3"

If you do want a new array, args=("$@") will assign them all to a new array in one shot. No need for the explicit for loop. You can then access the individual elements with ${args[0]} and the like.

args=("$@")

# Loop over arguments.
for arg in "${args[@]}"; do
echo "$arg"
done

# Access arguments by index.
echo "First = ${args[0]}"
echo "Second = ${args[1]}"
echo "Third = ${args[2]}"

(Note that using an explicit array the indices start at 0 instead of 1.)

How to pass all arguments passed to my Bash script to a function of mine?

The $@ variable expands to all command-line parameters separated by spaces. Here is an example.

abc "$@"

When using $@, you should (almost) always put it in double-quotes to avoid misparsing of arguments containing spaces or wildcards (see below). This works for multiple arguments. It is also portable to all POSIX-compliant shells.

It is also worth noting that $0 (generally the script's name or path) is not in $@.

The Bash Reference Manual Special Parameters Section says that $@ expands to the positional parameters starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is "$@" is equivalent to "$1" "$2" "$3"....

Passing some arguments:

If you want to pass all but the first arguments, you can first use shift to "consume" the first argument and then pass "$@" to pass the remaining arguments to another command. In Bash (and zsh and ksh, but not in plain POSIX shells like dash), you can do this without messing with the argument list using a variant of array slicing: "${@:3}" will get you the arguments starting with "$3". "${@:3:4}" will get you up to four arguments starting at "$3" (i.e. "$3" "$4" "$5" "$6"), if that many arguments were passed.

Things you probably don't want to do:

"$*" gives all of the arguments stuck together into a single string (separated by spaces, or whatever the first character of $IFS is). This looses the distinction between spaces within arguments and the spaces between arguments, so is generally a bad idea. Although it might be ok for printing the arguments, e.g. echo "$*", provided you don't care about preserving the space within/between distinction.

Assigning the arguments to a regular variable (as in args="$@") mashes all the arguments together like "$*" does. If you want to store the arguments in a variable, use an array with args=("$@") (the parentheses make it an array), and then reference them as e.g. "${args[0]}" etc. Note that in Bash and ksh, array indexes start at 0, so $1 will be in args[0], etc. zsh, on the other hand, starts array indexes at 1, so $1 will be in args[1]. And more basic shells like dash don't have arrays at all.

Leaving off the double-quotes, with either $@ or $*, will try to split each argument up into separate words (based on whitespace or whatever's in $IFS), and also try to expand anything that looks like a filename wildcard into a list of matching filenames. This can have really weird effects, and should almost always be avoided. (Except in zsh, where this expansion doesn't take place by default.)

How can I store a command in a variable in a shell script?

Use eval:

x="ls | wc"
eval "$x"
y=$(eval "$x")
echo "$y"

Propagate all arguments in a Bash shell script

Use "$@" instead of plain $@ if you actually wish your parameters to be passed the same.

Observe:

$ cat no_quotes.sh
#!/bin/bash
echo_args.sh $@

$ cat quotes.sh
#!/bin/bash
echo_args.sh "$@"

$ cat echo_args.sh
#!/bin/bash
echo Received: $1
echo Received: $2
echo Received: $3
echo Received: $4

$ ./no_quotes.sh first second
Received: first
Received: second
Received:
Received:

$ ./no_quotes.sh "one quoted arg"
Received: one
Received: quoted
Received: arg
Received:

$ ./quotes.sh first second
Received: first
Received: second
Received:
Received:

$ ./quotes.sh "one quoted arg"
Received: one quoted arg
Received:
Received:
Received:

Process all arguments except the first one (in a bash script)

Use this:

echo "${@:2}"

The following syntax:

echo "${*:2}"

would work as well, but is not recommended, because as @Gordon already explained, that using *, it runs all of the arguments together as a single argument with spaces, while @ preserves the breaks between them (even if some of the arguments themselves contain spaces). It doesn't make the difference with echo, but it matters for many other commands.

How to define a shell script with variable number of arguments?

The bash variables $@ and $* expand into the list of command line arguments. Generally, you will want to use "$@" (that is, $@ surrounded by double quotes). This will do the right thing if someone passes your script an argument containing whitespace.

So if you had this in your script:

outputfile=$1
shift
gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=$outputfile "$@"

And you called your script like this:

myscript out.pdf foo.ps bar.ps "another file.ps"

This would expand to:

gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=out.pdf foo.ps bar.ps "another file.ps"

Read the "Special Parameters" section of the bash man page for more information.

How to write a bash script that takes optional input arguments?

You could use the default-value syntax:

somecommand ${1:-foo}

The above will, as described in Bash Reference Manual - 3.5.3 Shell Parameter Expansion [emphasis mine]:

If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

If you only want to substitute a default value if the parameter is unset (but not if it's null, e.g. not if it's an empty string), use this syntax instead:

somecommand ${1-foo}

Again from Bash Reference Manual - 3.5.3 Shell Parameter Expansion:

Omitting the colon results in a test only for a parameter that is unset. Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.



Related Topics



Leave a reply



Submit