Search code examples
kshpipelineheredoc

KSH, read used in a pipeline


I'm trying to learn Here Documents IO-redirections in Korn Shell. I used "read" builtin to test the concepts.

I wrote a sample program as follows

#!/usr/bin/ksh

cat << ONE | wc -l | read word | if [ $word -eq 1 ]; then cat << TWO ; fi  | wc -l | read word | if [ $word -eq 2 ]; then cat << THREE ; fi 
1
ONE
1
2
TWO
1
2
3
THREE

I expect the output to be:

1
2
3

But the output is

[: argument expected

i think the $word variable is empty.

Then i rewrote the program as below which works fine:

cat << ONE | wc -l | { read word ; if [ $word -eq 1 ]; then cat << TWO ; fi ;} | wc -l | { read word ; if [ $word -eq 2 ]; then cat << THREE ; fi ;}
1
ONE
1
2
TWO
1
2
3
THREE

The output is as expected:

1
2
3

My question is about the first snippet:

  • why the "read word" command in the pipeline is not updating the word variable in the shell and the subsequent commands are not able to use it.
  • Also 'read word" doesn't write anything to the standard output so
    using it in a pipeline is not right, but i wanted to check it out.
  • But then, the command following the "read word" doesn't read anything from standard input so it should be fine.

Solution

  • Keep in mind that each side of a pipe (|) is a separate shell session.

    In your first attempt you have ... | wc -l | read word | if ..., so while the result of wc -l will be read and stored in the next shell session's variable word, this variable is not passed to the next shell session. And since the variable word is now undefined, your statement if [ $word -eq 1 ] becomes if [ -eq -1 ] and hence the error.

    In your second attempt your { read word ; if [ $word -eq 1 ]; then cat << TWO ; fi ;} construct represents a single shell session where the variable word is initialized (with the results of wc -l), and because this is still a single shell the variable can now be used in your if/then block.