[Techtalk] weirdness piping to a variable

Chris Wilson chris+linuxchix at aptivate.org
Wed Sep 11 12:43:23 UTC 2013


Hi Miriam,

On Wed, 11 Sep 2013, Miriam English wrote:

> echo "quick brown fox" | cut -d' ' -f2 | ( read a ; echo $a )
>
> It works, but it appears that I can only use "read" inside the parenthesised 
> part. I have no idea why. If I try to do it without the parentheses like 
> this:
>
> echo "quick brown fox" | cut -d' ' -f2 |  read a ; echo $a
>
> nothing happens. I don't understand why.
>
> As I understand it, the part inside parentheses is another process. I can get 
> variables into it, but unfortunately not out.
>
> a="one" ; echo "two" | (read b ; echo "$a and $b") ; echo "$a and $b."

Any command that contains a semicolon is two separate commands, split 
around the semicolon, and executed one after the other. You probably 
already know that, but bear it in mind.

Any command that contains a pipe, splits into multiple separate processes, 
one for each stage of the pipe. The first part executes in the parent 
process. So taking your example:

   echo "quick brown fox" | cut -d' ' -f2 |  read a ; echo $a

The first process executes 'echo "quick brown fox"; echo $a', and then 
prompts you for another command.

The second process executes "cut -d' ' -f2", and terminates when it 
finishes.

The third process executes "read a", and terminates when it finishes.

Processes don't share variables, so the results of "read a" are locked in 
process 3's memory, and die with it. However, they do *inherit* variables, 
so process 3 starts with a copy of any variables set in process 1, but 
can't modify them.

> It's nice to be able to pipe values into a variable because it maintains 
> the left to right conceptual flow and makes it easier for me to 
> understand what I was doing when I come back much later, but it isn't 
> much help if I can't use the variables outside the parentheses.

Yes it is nice, but it's not how pipes work. You either need to rearrange 
your pipes so that the set variables stay at the beginning, for example:

   read a < <(echo "quick brown fox" | cut -d' ' -f2); echo $a

Or do more work in the subshell (third process), as you did with 
parentheses (a while loop works too), or write the results to a file and 
read them back:

   echo "quick brown fox" | cut -d' ' -f2 > /tmp/tempfile
   read a < /tmp/tempfile

Cheers, Chris.
-- 
Aptivate | http://www.aptivate.org | Phone: +44 1223 967 838
Citylife House, Sturton Street, Cambridge, CB1 2QF, UK

Aptivate is a not-for-profit company registered in England and Wales
with company number 04980791.



More information about the Techtalk mailing list