5

I have a script that reads from a pipe in a loop and runs an expect script and a normal shell script in the loop. Both scripts run ssh to another server to grab a piece of data. For example:

cat /tmp/file | while read a b c d do s=`expect-script server1 $b` c=`ssh $b normal-script` echo $s $c done 

Even though there are many lines in /tmp/file, the script quits after processing the first line. I suspect that the expect script is swallowing all of stdin so that when it returns, there is nothing left to read. How can I avoid this? I don't want any of the scripts I call to read from the stdin of the main script.

5
  • possible duplicate of "while read line" returns early when calling ssh "mysql..." Commented Jun 21, 2014 at 5:18
  • The possible duplicate is similar, but not identical. I can't use the -n option of ssh, because the ssh is called by the Expect script, which requires reading from stdin. I will play around with the redirection solution to see if that works for me. Commented Jun 21, 2014 at 5:31
  • 1
    Ah I see. Check the solution of this problem in different in another stackexchange network unix.stackexchange.com/questions/107800/… Commented Jun 21, 2014 at 5:40
  • Yes, that solution helped me get it to work, especially Richard Hansen's comment. Thank you! Commented Jun 21, 2014 at 16:59
  • @masegaloeh, I suggest adding an answer with that link, which Justin can accept, so that this question doesn't remain marked as unanswered. Commented Jun 21, 2014 at 20:56

3 Answers 3

5

It's actually ssh that's slurping up stdin. Just add the -n option:

 c=$( ssh -n $b normal-script ) 

If you don't want to do that, you can have your shell while loop read from a different file descriptor, leaving stdin untouched:

while read -u3 a b c d do s=$( expect-script server1 $b ) c=$( ssh $b normal-script ) echo $s $c done 3< /tmp/file 

(assuming bash/ksh/zsh for the read -u option)

3
cat /tmp/file | while read a b c d do { s=`expect-script server1 $b` c=`ssh $b normal-script` echo $s $c } < /dev/null done 

The { command... } syntax allows you to apply redirection or piping to a sequence of commands.

I'll also note that you don't need cat in your example. You could do this:

while read a b c d do ... done < /tmp/file 
0

Also, generally speaking, if you don't want some command to use current STDIN, you provide it with different one using <.

E.g.

 s=`expect-script server1 $b < /dev/null` 

would make "expect-script" read it's STDIN from /dev/null (which happens to just return EOF) instead of consuming your current one (from /tmp/file)

You can also use | to provide some separate STDIN just for that command, e.g.

 s=`cat /tmp/stdin_for_expect | expect-script server1 $b` c=`cat /tmp/stdin_for_ssh | ssh $b normal-script` 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.