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.

Justin
  • 51
  • 1
  • 2
  • possible duplicate of ["while read line" returns early when calling ssh "mysql..."](http://serverfault.com/questions/513858/while-read-line-returns-early-when-calling-ssh-mysql) – masegaloeh Jun 21 '14 at 05: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. – Justin Jun 21 '14 at 05:31
  • 1
    Ah I see. Check the solution of this problem in different in another stackexchange network http://unix.stackexchange.com/questions/107800/using-while-loop-to-ssh-to-multiple-servers – masegaloeh Jun 21 '14 at 05:40
  • Yes, that solution helped me get it to work, especially Richard Hansen's comment. Thank you! – Justin Jun 21 '14 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. – Cristian Ciupitu Jun 21 '14 at 20:56

2 Answers2

4

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)

glenn jackman
  • 4,320
  • 16
  • 19
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
Kenster
  • 2,082
  • 16
  • 15