bash Shell 脚本循环遍历文件,ssh 进入远程服务器并在失败时继续复制文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21895387/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 09:38:19  来源:igfitidea点击:

Shell script loop through file, ssh into remote server and copy files continue on fail

linuxbashshellssh

提问by gorelative

Given the following file, I cannot figure out how to continue to iterate through the lines one by one without it exiting on first failure of the inner most remote ssh command.

鉴于以下文件,我无法弄清楚如何继续逐行遍历行而不在内部最远程 ssh 命令第一次失败时退出。

The basic premise is this script ssh's to a remote server defined as INPUT_FILEas USERand copies a bunch of files off to a remote location for backup.. the actual backup script is in backup.sh. which controller.shexecutes.

其基本前提是这个脚本的ssh是被定义为一个远程服务器INPUT_FILE作为USER和副本一堆文件关闭到远程位置用于备份..实际的备份脚本中backup.sh。哪个controller.sh执行。

My problem is that if the backup.sh throws an error, something like a permission denied for cpthe whole whileloop finishs and it won't connect to any of the remaing servers in my INPUT_FILE. I know this because I have purposely put in place permissions on various servers to test this scenario.

我的问题是,如果 backup.sh 引发错误,cp则整个while循环的权限被拒绝之类的事情会完成,并且它不会连接到我的 .sh 文件中的任何剩余服务器INPUT_FILE。我知道这一点是因为我特意在各种服务器上设置了权限来测试这个场景。

How can i iterate through the files, and wait for the first ssh command to complete and force it to go to the next line without exiting.

我如何遍历文件,并等待第一个 ssh 命令完成并强制它转到下一行而不退出。

controller.sh

控制器文件

INPUT_FILE=
USER=
SCRIPT_DIR=/opt/sapdownloads/MikesUtilities/backups
BACKUP_DIR=$SCRIPT_DIR/data
DATE=`date +%m%d%y`
LOG_FILE=$SCRIPT_DIR/logs/backup.controller.log


##
# Create The Log dir and log files
##
function log(){
   echo -e ${*}
   echo -e "[${USER}][`date`] - ${*}" >> ${LOG_FILE}
}


#Iterate through the input file line by line

cat $INPUT_FILE | while read l;do {
   #Split the line by spaces into an array
   line=($l)
   #make sure server is lower case
   SERVER=`echo ${line[1]} | tr [:lower:] [:upper:]`
   #make sure tier is uppercase
   TIER=`echo ${line[0]} | tr [:upper:] [:lower:]`
   log "###################################"
   log "#  Tier: $TIER | SERVER: $SERVER  #"
   log "###################################"
   log "Making Sure we can login to the Server"
   CHK=`ssh -t -q -o "BatchMode yes" -o "ConnectTimeout 5" -l $USER $SERVER "echo success"`;
   if [ "success" = $CHK ] >/dev/null 2>&1
   then
      CPDIR=$BACKUP_DIR/$TIER/$SERVER/$DATE
      log "Creating new backup directories in $CPDIR"
      #make the new backup directory in $BACKUP_DIR
      mkdir -p $BACKUP_DIR/$TIER/$SERVER/$DATE/etc
      mkdir -p $BACKUP_DIR/$TIER/$SERVER/$DATE/home


      log "Executing Remote Backup Script"
      ret=`ssh -n -t -q -o "BatchMode yes" -o "ConnectTimeout 5" -l $USER $SERVER "/bin/bash $SCRIPT_DIR/backup.sh $CPDIR; echo $?"`
      echo "return: [$ret]"
      if [ $ret -eq 0 ]; then
         echo "Success. Aborting"
         break
      fi
   else
      printf "${i}\tUnable to connect to host\n" >> $ERRORS;
   fi
} </dev/null; done

backup.sh

备份文件

#!/bin/bash
CPDIR=
DATE=`date +%m%d%y`
SCRIPT_DIR=/opt/sapdownloads/MikesUtilities/backups
LOG_FILE=$SCRIPT_DIR/logs/backup.log
SIDADM_HOME=/home/${sapsid}adm
ORASID_HOME=/home/ora${sapsid}
ORACLE_HOME=/home/oracle
cpErrors=()
message=""
SENDTO="[email protected]"
SENDFROM="[email protected]"

##
# Create The Log dir and log files
##
function log(){
   #echo -e ${*}
   echo -e "[${USER}][`date`] - ${*}" >> ${LOG_FILE}
}

function compileMessage(){
   message="Unable to CP one or more files from the server $HOSTNAME \n\n"
   for i in "${cpErrors[@]}"
   do
      message+="${i}\n"
   done
}

function sendMail(){
   compileMessage

   echo -e $message | mail -s "OS Backup Errors" -r $SENDFROM $SENDTO
}

cd /etc
#copy fstab
if [ -d "oratab" ]; then
   log "Copying oratab to $CPDIR/etc"
   cp oratab $CPDIR/etc
fi
#Copy fstab
if [ -d "fstab" ]; then
   log "Copying fstab to $CPDIR/etc"
   cp fstab $CPDIR/etc
fi

#make sure that folder exists first
if [ -d "$ORASID_HOME" ]; then

   #Test to make sure we can access the folder
   if [ -w "$ORASID_HOME" ]; then
      log "Copying $ORASID_HOME to $CPDIR/home"
      cp -rf $ORASID_HOME $CPDIR/home
   else
      #if we cant access that folder, send an email
      log "Unable to cp $ORASID_HOME to $CPDIR/home"
      cpErrors+=($ORASID_HOME)
   fi

fi

#make sure that folder exists first
if [ -d "$SIDADM_HOME" ]; then

   #Test to make sure we can access the folder
   if [ -w "$SIDADM_HOME" ]; then
      log "Copying $SIDADM_HOME to $CPDIR/home"
      cp -rf $SIDADM_HOME $CPDIR/home
   else
      #if we cant access that folder, send an email
      log "Unable to cp $SIDADM_HOME to $CPDIR/home"
      cpErrors+=($SIDADM_HOME)
   fi

fi

#make sure that folder exists first
if [ -d "$ORACLE_HOME" ]; then

   #Test to make sure we can access the folder
   if [ -w "$ORACLE_HOME" ]; then
      log "Copying $ORACLE_HOME to $CPDIR/home"
      cp -rf $ORACLE_HOME $CPDIR/home
   else
      #if we cant access that folder, send an email
      log "Unable to cp $ORACLE_HOME to $CPDIR/home"
      cpErrors+=($ORACLE_HOME)
   fi

fi


if [ ${#cpErrors[@]} != 0 ]; then
   log "Sending Email of cp errors"
   sendMail
fi

回答by julumme

As you probably have guessed, sshis eating your input from the while loop, and that's why it's failing. Actually I'm not 100% sure why -nis not working in this case, but we can work around it.

正如您可能已经猜到的那样,ssh正在从 while 循环中吃掉您的输入,这就是它失败的原因。实际上我不是 100% 确定为什么-n在这种情况下不起作用,但我们可以解决它。

Since I don't have your backup scripts (nor the general setup), I simplified the script quite a bit, but I think the general idea is same. Go through input file that server information, and try to find a server we can login to, and then see if we can successfully execute a script there

由于我没有您的备份脚本(也没有一般设置),我对脚本进行了相当多的简化,但我认为总体思路是相同的。通过输入文件中的服务器信息,并尝试找到我们可以登录的服务器,然后看看我们是否可以在那里成功执行脚本

I call a simple script on a remote machine that waited for couple of seconds, and returned an exit code. You should add some exit codes to your Backup.sh, so that you can check what was returned from the remote command, and then act on it.

我在等待几秒钟的远程机器上调用一个简单的脚本,并返回一个exit code. 您应该将一些退出代码添加到您的Backup.sh,以便您可以检查从远程命令返回的内容,然后对其进行操作。

So with adding curly bracesto the while (and </dev/null), and retrieve exit codefrom your remote script, I was able to go through the list until a successful remote script execution was done:

因此,通过在 while(和)中添加花括号</dev/null,并从远程脚本中检索退出代码,我能够遍历列表,直到成功执行远程脚本:

cat $INPUT_FILE | while read l;do {

SERVER=($l)
CHK=`ssh -t -q -o "BatchMode yes" -o "ConnectTimeout 5" -l $USER $SERVER "echo success"`;

if [ "success" = $CHK ] >/dev/null 2>&1
then
  ret=`ssh -n -t -q -o "BatchMode yes" -o "ConnectTimeout 5" -l $USER $SERVER '/home/username/timer.sh testvar;echo $?'`
  echo "return: [$ret]"
  if [ $ret -eq 0 ]; then
       echo "Success. Aborting"
       break
  fi
else
  printf "${i}\tUnable to connect to host\n";
fi
} < /dev/null; done

Hope it helps

希望能帮助到你