TorosFanny
TorosFanny

Reputation: 1732

How to make echo compatible with read in bash?

I tried this:

qs@BF:~$ echo aaa | read c
qs@BF:~$ echo $c

It gives nothing, which means $c is an empty macro.

But why the following one works:

qs@BF:~$ cat trim.hs | read cc
qs@BF:~$ echo $cc
import qualified Data.Text as T

It correctly gives the first line of trim.hs

There seams to be an exception when echo piped with read. Am I right? Could you help me to make echo compatible with read? Please.

Upvotes: 2

Views: 126

Answers (2)

declension
declension

Reputation: 4185

I think the underlying problem here is subshells that read is run in. These won't (always) propagate values to your invocation.

From the POSIX read standard it outlines how using read within subshells will not be visible to the caller:

If it is called in a subshell or separate utility execution environment, such as one of the following:

(read foo)
nohup read ...
find . -exec read ... \;

it shall not affect the shell variables in the caller's environment.

And noting in these shell tips:

POSIX allows any or all commands in a pipeline to be run in subshells, and which command (if any) runs in the main shell varies greatly between implementations — in particular Bash and ksh differ here. The standard idiom for overcoming this problem is to use a here document:

IFS= read var << EOF
$(foo)
EOF

Upvotes: 2

glenn jackman
glenn jackman

Reputation: 246744

Neither of these "work"

echo aaa | read c
cat trim.hs | read cc

In bash, commands in a pipeline are all executed in subshells. So, the read command sets the variable c in a subshell, but then that subshell exits and its environment disappears

To demonstrate, let's query the value of $c in the subshell using a grouping construct:

unset c
echo 123 | { read c; echo in subshell: ">$c<"; }
echo in parent: ">$c<"

outputs

in subshell: >123<
in parent: ><

bash does have a setting to allow the last command in a pipeline to run in the current shell:

set +m               # job control must be disabled
shopt -s lastpipe    # enable the option
unset d
echo 456 | read d
echo ">$d<"
>456<

Upvotes: 3

Related Questions