1

If I run the following script of command substitution:

var=$(ls)
echo $var

it works as expected -- the output is the results of ls command. But if I assign the variable using read:

read var
echo $var

in which $(ls) is the input to read, the output is the literal

$(ls)

instead of the output of the ls command.

I don't understand why there is such a difference because I think the contents of variable var should be the same in both cases and therefore the shell should treat the echo command in both exactly the same way.

Could you please give an explanation?

3
  • please provide the full read var line, I don't see $(ls) being the input here. – pLumo Sep 21 '18 at 7:04
  • Bare read will just take a line of what you type into the shell. Specifically, it reads stdin stream. So whatever goes into var in read var is what you've typed. That's why it makes no sense how you got $(ls) string into it unless you typed that out while executing read – Sergiy Kolodyazhnyy Sep 21 '18 at 7:20
  • 1
    On another note before you get any ideas: Why not parse ls (and what do do instead)? – David Foerster Sep 24 '18 at 10:50
3

Command substitution is a shell expansion, and Bash doesn't perform expansions on the input to read.

This is a good thing, because read is supposed to capture whatever nonsense (or brilliance) the naive (or expert) user typed.

Try entering any input that the shell would usually expand, and you will find the same thing happens...

$ var=~          # ~ was expanded before assignment
$ echo $var
/home/zanna
$ read -r var
~
$ echo $var
~

There are some sort-of exceptions to this - read treats backslash characters as escapes

The backslash character ‘\’ may be used to remove any special meaning for the next character read and for line continuation.

This is almost never what you actually want (you want read to capture whatever the user typed including any backslashes), so you should habitually use the -r flag with read (like I have done in my examples):

-r

If this option is given, backslash does not act as an escape character. The backslash is considered to be part of the line. In particular, a backslash-newline pair may not be used as a line continuation.

The other exception is that the input is split into fields in a way similar to word-splitting, so you can assign to multiple variables:

$ read -r var
one two three
$ echo $var
one two three
$ read -r baa ram ewe
one two three
$ echo $ram
two

Quotes are from this section of the Bash manual - scroll down to find read, or run help read in the shell for a shorter version.

0

var=$(ls) executes command ls and assigns the output to a variable In the second case, it just assigns the string you entered to a variable, there is no execution happening. It is just a string assigned to a variable, bash does not do anything with it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.