Why does deploying a bash script loop work only once?

I have some simple scripts that are designed to sequentially chain together to run a specific script on a variety of servers, all of which are listed in the file, one per line.

The deployment of a single server script contains the following:

1 #!/bin/bash 2 3 file=$1 4 host=$2 5 6 scp ${file} ${host}:/tmp/ 7 USER=`whoami` 8 ssh -t -t $USER@ ${host} /tmp/${file} 9 10 ssh "${host}" /bin/rm /tmp/${file} 11 exit 

It works fine on a script. I have that yum install tomcat and symlinks hasoop / hbase configs in a shared class directory.

The second main file is deploy-all.sh, which is designed to analyze the list of hosts and launch the deployment script for all of them:

  1 #!/bin/bash 2 3 script=$1 4 5 cat dumbo-hosts | while read fileline 6 do 7 echo ${fileline} 8 ./deploy.sh ${script} ${fileline} 9 10 sleep 10 11 done 

It happens that the script is run once, and then the for loop breaks off ... I got something like the following output:

 $ ./deploy-all.sh setup-tomcat.sh line is hadoop01.myhost setup-tomcat.sh 100% 455 0.4KB/s 00:00 tcgetattr: Inappropriate ioctl for device hadoop02.myhost hadoop03.myhost hadoop04.myhost <succesful output of hadoop01 task> ... Connection to hadoop01.myhost closed. 

If I comment on ssh commands, the loop runs successfully across all 4 hosts, so I assume this is something related to disabling stdio after ssh happens. Also, the tcgatattr error concerns me somewhat.

How can I get around this? What exactly causes the tcgetattr error (I'm not even sure if this is related)? Actually, not much has been done with shell scripts, so sorry if I miss something really obvious here, any help would be appreciated.

0
source share
2 answers

This is a problem with ssh reusing the descriptor of the stdin file at startup as part of the subprocess.

The workaround is to use '-n' when invoking ssh from a nonterminal context.

 option=-n tty -s 2>/dev/null && option= scp ${file} ${host}:/tmp/ ssh $option -t ${host} /tmp/${file} ssh $option ${host} rm /tmp/${file} 
+1
source

I solved this using bash arrays to temporarily store strings in the array to avoid stdin interruption ... But this seems wrong ... If anyone has a better way around this, please let me know.

Here is my solution:

  1 #/bin/bash 2 3 #myscript = $1 4 count=0 5 6 declare -a lines 7 8 while read line 9 do 10 lines[$count]=$line 11 ((count++)) 12 done < dumbo-hosts 13 14 for i in "${lines[@]}" 15 do 16 echo "$i" 17 ./deploy.sh "$1" "${i}" 18 done 
0
source

All Articles