Home » Questions » Computers [ Ask a new question ]

Shell scripting input redirection oddities

Shell scripting input redirection oddities

"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."

Asked by: Guest | Views: 267
Total answers/comments: 4
Guest [Entry]

"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"
Guest [Entry]

"#!/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."
Guest [Entry]

"This has already been answered correctly, but the solution has not been stated yet. Use ksh, not bash. Compare:

$ echo 'echo ""hello world"" | read var1 var2
echo $var1
echo $var2' | bash -s

To:

$ echo 'echo ""hello world"" | read var1 var2
echo $var1
echo $var2' | ksh -s
hello
world

ksh is a superior programming shell because of little niceties like this. (bash is the better interactive shell, in my opinion.)"
Guest [Entry]

read var1 var2 < <(echo "hello world")