[Techtalk] weirdness piping to a variable

Miriam English mim at miriam-english.org
Sun Sep 15 08:26:46 UTC 2013


Hi Chris,

Sorry about the very slow response. I was distracted by further thoughts 
and experiments on this... and then by a computer becoming unusable 
(unrelated to this question), before a 2 hr session between 2am and 4am 
this morning when inspiration woke me and I fixed the computer. Yay!

Anyway, back to the point at hand.

Thanks Chris, for the very clear explanation. I now see why this doesn't 
work.

But this also makes the problem sharper to me. One of the nice things 
about Unix/Linux is the way devices, files, and so on are treated alike. 
But variables are an exception with entirely different ways of getting 
stuff into them. I understand the need to localise variables to a 
particular process and its children (though I have a feeling one of the 
shells doesn't have this problem with pipes), however I'm surprised 
there isn't something that takes the standard output and delivers it to 
a variable in a manner consistent with the rest of the way Unix/Linux 
moves data. And in my searches online, I see I'm not the only person 
bothered by this.

No matter. It is what it is. :) Onward to more important problems.

Thanks for the explanation, Chris.

Best wishes,

	- Miriam


Chris Wilson wrote:
> 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.

-- 
If you don't have any failures then you're not trying hard enough.
  - Dr. Charles Elachi, director of NASA's Jet Propulsion Laboratory
-----
Website: http://miriam-english.org
Blogs:   http://miriam-e.dreamwidth.org
          http://miriam-e.livejournal.com




More information about the Techtalk mailing list