2

I have set an environment variable and want to use it when calling a command, but no dice.

The full command, without variable, works:

nacho@WouldntYouLikeToKnow ~ % ls -la ~/Downloads             
total 8675309
drwx------+ 16 nacho  staff        512 Sep 28 10:30 .
drwxr-x---+ 29 nacho  staff        928 Sep 29 10:39 ..

Now I set a variable and try to use it, but it fails:

nacho@WouldntYouLikeToKnow ~ % export testing="-la ~/Downloads"

nacho@WouldntYouLikeToKnow ~ % ls $testing ls: invalid option --
usage: ls [-@ABCFGHILOPRSTUWabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]

Kusalananda
  • 333,661
IMTheNachoMan
  • 419
  • 1
  • 7
  • 18

1 Answers1

4

It's almost always the wrong approach to stuff several separate strings (arguments) into a single string, at least if you need to extract those separate strings again.

What you're doing works in the bash shell (assuming you used $HOME in place of ~, as the shell does not do tilde expansion inside double quotes) because it splits the unquoted variable expansion on the space characters in the string (on any character in $IFS; and also applies filename globbing to the generated words), while the zsh shell does not do that.

Note that it only works in bash since there are no other space, tab or newline characters in your string and since the string also does not contain filename globbing characters. Your approach would most definitely not work in bash if the pathname had a space in it, for example, or if you want to list the contents of a directory called *.

The correct way to store separate command line arguments in a variable in both shells is to use an array:

args=( -la ~/Downloads )

or

args=( -l -A ~/Library/'Application Support' )

In the bash shell, you would then use this as

ls "${args[@]}"

Here, "${args[@]}" expands to a list consisting of the elements of the args array, each individually quoted.

In the zsh shell, you could do the same thing or just use

ls $args

Here, the zsh shell would expand the array args to separate elements, each turning into an argument for ls, but it would not (by default) split those elements or apply filename globbing to them.

These examples also leave the tilde unquoted, allowing the shell to expand it into the pathname of the user's home directory. This expansion would happen when assigning to the args arrays, not when using the value.

Related:

Kusalananda
  • 333,661