63

When I try to use the read command in Bash like this:

echo hello | read str
echo $str

Nothing echoed, while I think str should contain the string hello. Can anybody please help me understand this behavior?

1

9 Answers 9

62

The read in your script command is fine. However, you execute it in the pipeline, which means it is in a subshell, therefore, the variables it reads to are not visible in the parent shell. You can either

  • move the rest of the script in the subshell, too:

    echo hello | { read str
      echo $str
    }
    
  • or use command substitution to get the value of the variable out of the subshell

    str=$(echo hello)
    echo $str
    

    or a slightly more complicated example (Grabbing the 2nd element of ls)

    str=$(ls | { read a; read a; echo $a; })
    echo $str
    
Sign up to request clarification or add additional context in comments.

4 Comments

Awesome examples! I did have to slightly tweak it on OSX by putting spaces inside the curly braces, and a semi-colon after the echo, like this: str=$(ls | { read a; read a; echo $a; })
@javadba: It is not required twice. The given example returns the second item from ls. With a single read a you would get the first item. Don't ask me why the answerer chose this example.
To read three (or more) IFS-separated columns into variables one can do 'read VAR_1 VAR_2 VAR_3`.
keeps biting me. Should be documented in the man page..
43

Other bash alternatives that do not involve a subshell:

read str <<END             # here-doc
hello
END

read str <<< "hello"       # here-string

read str < <(echo hello)   # process substitution

1 Comment

You can use a process for the here string as well such as read A B C <<< $(echo 'aaa bbb ccc')
8

Typical usage might look like:

i=0
echo -e "hello1\nhello2\nhello3" | while read str ; do
    echo "$((++i)): $str"
done

and output

1: hello1
2: hello2
3: hello3

Comments

4

The value disappears since the read command is run in a separate subshell: Bash FAQ 24

Comments

2

To put my two cents here: on KSH, reading as is to a variable will work, because according to the IBM AIX documentation, KSH's read does affects the current shell environment:

The setting of shell variables by the read command affects the current shell execution environment.

This just resulted in me spending a good few minutes figuring out why a one-liner ending with read that I've used a zillion times before on AIX didn't work on Linux... it's because KSH does saves to the current environment and BASH doesn't!

Comments

0

I really only use read with "while" and a do loop:

echo "This is NOT a test." | while read -r a b c theRest; do  
echo "$a" "$b" "$theRest"; done  

This is a test.
For what it's worth, I have seen the recommendation to always use -r with the read command in bash.

Comments

-1

You don't need echo to use read

 read -p "Guess a Number" NUMBER

Comments

-2

Another alternative altogether is to use the printf function.

printf -v str 'hello'

Moreover, this construct, combined with the use of single quotes where appropriate, helps to avoid the multi-escape problems of subshells and other forms of interpolative quoting.

2 Comments

If that's all you're trying to achieve, you might as well do str='hello. I think the point here is to capture the output of a command into a variable.
This is actually a reasonable answer. According to man bash, under "SHELL BUILTIN COMMANDS -> printf": The -v option causes the output to be assigned to the variable var rather than being printed to the standard output.
-6

Do you need the pipe?

echo -ne "$MENU"
read NUMBER

2 Comments

-1: your echo and read commands are not connected in any way.
The poster clearly wants an automated way to populate a variable without having to enter it manually.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.