Singh Singh - 13 days ago 5
Bash Question

Assigning variables values in a better way

I have a written a bash script which uses number of parameters.
I have assigned variables in the following format.


The arguments are optional, and it runs without them as well
For example :

./ x y ...

both cases are working fine.

I am looking for a better approach, from design point of view as I don't like the way the variables are getting the value.

it will not look nice if in the future my arguments increase till 9



You can use read combined with herestring and the quote reconstruction ability of printf:

read x y z k <<<$(printf " %q" "$@")

By example:

$ cat example.bash
read x y z k <<<$(printf " %q" "$@")
echo "x=[$x]"
echo "y=[$y]"
echo "z=[$z]"
echo "k=[$k]"

$ ./example.bash a b "c d"
z=[c d]

So, what's going on here? Let's work from the inside out.

printf " %q" "$@" quotes the arguments it's given in a way equivalent to the original command line arguments. Without this quoting reconstruction, command line arguments with spaces would be treated as separate arguments even if originally quoted. To see what I mean, try sorontar's answer, just read x y z w <<<"$@": z is assigned "c" and k is assigned "d".

read receives the reconstituted command line, then assigns every non-escaped-space separated string into the given variables, left to right.

Back to our example:

  • "$@" is essentially a b "c d"
  • printf " %q" "$@" is a b c\ d
  • read x y z k <<<"a b c\ d" is a hard-coded representation of what you want.

While this is compact and extensible, it's also tricky. If your script takes arguments representing options (script behavior changes based on presence of absence of said arguments) then I'd suggest using getopts. If, however, your script takes many arguments representing values (like inputs into a matrix calculation) then reading into an array (read -a) might be easier to understand.

You might also want to handle the case where no command line arguments are provided. That requires a slight elaboration:

read x y z k <<<$([ 0 -eq $# ] && echo '' || printf " %q" "$@")

In this variant, the number of arguments are checked and if there are some, then the printf requoting business is performed.