Help with UNIX READ command usage..

Tested on : bash
Will be implementing on : ksh

I dont know if this is weird , or my idea of Unix stdin or stdout is completely messed up , but if I use the following command, I am getting a proper output.

ls -l | head -1 | while read a ; do echo $a ;done

and the output is soemthing like total 32

But, on the contrary , if I use

ls -l | head -1 | read a ; echo $a

it yields an empty value

My idea was , as because the commands are piped , the output of ls command will flow to standard input and will be read to the variable a.
But , its happening only when I used the while-read loop , and not the stand alone read .

Am I missing something here ? Please help.

Thanks
Kumarjit.

In most shells read a is executed in a subshell. This means that once the pipeline is finished and the subshell with read a is finished, the value of variable $a is not retained. There are various ways to get around this, but the most straight forward in this case is the use of command substitution: a=$( .. )

cmd | read a

You can think it like it looks or how it works in memory.
I'm happy that Korn has thinked as the pipe syntax idea has been. Even you need make some shared mem using to offer the result.

So use ksh if you like to use cmd | read variable(s).

# works only in ksh, not in Bourne shell or bash or dash or ...
ls -l | head -1 | read a 
echo $a

# pipe is only stdout-stdin channel between process. => read has also own env. So read set variable and die.
# Korn idea is to support how it looks => a is global variable, child process read and set value to the a.

# works in every sh-shells:
read <<EOF
$(ls -l | head -1 )
EOF
echo $a

# or
a=$(ls -l | head -1 )
echo $a

This example show the difference between ideas: (do it using bash and ksh).

a=1000
ls -l | head -1 | read a
echo $a

Next example is nice:

f=1111
ls -1 | while read f
do
        echo $f
done
echo "F $f"

Do it using bash, dash, ksh.

Always avoid unsafe/complex here documents

read a <<EOF
`ls -l | head -1`
EOF
echo $a

Instead do

a=`ls -l | head -1`
echo $a

$(...) is Posix, old Unix shells need `...`
Posix allows nested $(... $(...)).

As a last less good alternative you can place the echo in an explicit subshell:

ls -l | head -1 | (read a; echo $a)

I'm not sure why this should be less acceptable. Would you mind to explain? At least you could do some shell computing with the variable read and output the result:

$ ls -l | head -1 | { read a; compute; sth; different; echo $result; }

Rule of thumb:
do the most in the main shell.
The exception proves the rule.