Why does bash loop deploy script only seem to work

2019-08-27 01:27发布

I have a few simple scripts that are intended to daisy chain together to run a specific script on a set of servers all listed out in a file, one per line.

The single server deploy 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 installs tomcat and symlinks hadoop/hbase configs to the shared class directory.

The second major file is deploy-all.sh which is intended to parse a list of hosts and run the deploy script to 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

What happens is that the script runs once, and then the for loop is broken... 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 out the ssh commands the loop runs succesfully through all 4 hosts so I presume it's something involving stdio getting cut off once the ssh occurs. In addition the tcgatattr error concerns me somewhat.

How can I get around this? What exactly is causing the tcgetattr error(I'm not even sure if it's related)? Haven't really done much with shell scripts so sorry if I'm missing something really obvious here, any help would be appreciated.

2条回答
该账号已被封号
2楼-- · 2019-08-27 01:46

It's a problem with ssh reusing the stdin file descriptor when running as part of the subprocess.

The workaround is to use '-n' when invoking ssh from a non-terminal 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}
查看更多
老娘就宠你
3楼-- · 2019-08-27 01:48

I solved this by using bash arrays to temporarily store the lines into an array to avoid the stdin interruption... But it feels wrong... If anyone has a better way of getting around this, please let me know.

Here's 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
查看更多
登录 后发表回答