BK_STATARGS
is a variable whose content is the 7-character string -f '%z'
. First, let's see what happens in the command
stat "${BK_STATARGS}" test.txt
The shell first parses the command into a syntax tree, which here consists of a single simple command, with three tokens: stat
, the result of the expansion of ${BK_STATARGS}
, and test.txt
. Then the shell expands the value of the variable, in order to determine the second word, which is -f '%z'
(that same 7-character string). Finally the shell executes the command in the first word, passing the subsequent words as command line arguments, so stat
is executed with two arguments -f '%z'
and test.txt
.
Let's now turn to the more complex command
stat ${BK_STATARGS} test.txt
The processing is the same until the expansion of the value of the variable. Since the variable substitution is not in double quotes, its value is treated as a whitespace-separated list of words. There is one whitespace character in the string, so it is split into two words, and stat
receives three arguments: -f
, '%z'
and test.txt
.
The single quotes are part of shell syntax: they are recognized at the parsing stage. They have no special meaning when they're in a string, even if the string gets split after variable expansion.
Since %
and z
are not special characters, you don't need to quote them:
typeset -r BK_STATARGS="-f %z"
typeset FILE_SIZE2=$(stat ${BK_STATARGS} test.txt)
In general, to pass multiple arguments to a command, you need to use an array instead of a string.
typeset -a BK_STATARGS; BK_STATARGS=(-f '%z')
typeset FILE_SIZE2=$(stat "${BK_STATARGS[@]}" test.txt)
"${BK_STATARGS[@]}"
is the syntax to expand an array into its list of elements. Even though it looks like a single word due to the double quotes, it's actually split into multiple words due to the [@]
subscript, working like "$@
.