Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shell scripting input redirection oddities

Tags:

Can anyone explain this behavior? Running:

#!/bin/sh echo "hello world" | read var1 var2 echo $var1 echo $var2 

results in nothing being ouput, while:

#!/bin/sh echo "hello world" > test.file read var1 var2 < test.file echo $var1 echo $var2 

produces the expected output:

hello world 

Shouldn't the pipe do in one step what the redirection to test.file did in the second example? I tried the same code with both the dash and bash shells and got the same behavior from both of them.

like image 964
Ryan Ahearn Avatar asked Aug 05 '08 19:08

Ryan Ahearn


2 Answers

A recent addition to bash is the lastpipe option, which allows the last command in a pipeline to run in the current shell, not a subshell, when job control is deactivated.

#!/bin/bash set +m      # Deactiveate job control shopt -s lastpipe echo "hello world" | read var1 var2 echo $var1 echo $var2 

will indeed output

hello world 
like image 181
chepner Avatar answered Oct 18 '22 14:10

chepner


#!/bin/sh echo "hello world" | read var1 var2 echo $var1 echo $var2 

produces no output because pipelines run each of their components inside a subshell. Subshells inherit copies of the parent shell's variables, rather than sharing them. Try this:

#!/bin/sh foo="contents of shell variable foo" echo $foo (     echo $foo     foo="foo contents modified"     echo $foo ) echo $foo 

The parentheses define a region of code that gets run in a subshell, and $foo retains its original value after being modified inside them.

Now try this:

#!/bin/sh foo="contents of shell variable foo" echo $foo {     echo $foo     foo="foo contents modified"     echo $foo } echo $foo 

The braces are purely for grouping, no subshell is created, and the $foo modified inside the braces is the same $foo modified outside them.

Now try this:

#!/bin/sh echo "hello world" | {     read var1 var2     echo $var1     echo $var2 } echo $var1 echo $var2 

Inside the braces, the read builtin creates $var1 and $var2 properly and you can see that they get echoed. Outside the braces, they don't exist any more. All the code within the braces has been run in a subshell because it's one component of a pipeline.

You can put arbitrary amounts of code between braces, so you can use this piping-into-a-block construction whenever you need to run a block of shell script that parses the output of something else.

like image 43
flabdablet Avatar answered Oct 18 '22 16:10

flabdablet