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
Shell script loop through file, ssh into remote server and copy files continue on fail
提问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_FILE
as USER
and copies a bunch of files off to a remote location for backup.. the actual backup script is in backup.sh
. which controller.sh
executes.
其基本前提是这个脚本的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 cp
the whole while
loop 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, ssh
is eating your input from the while loop, and that's why it's failing. Actually I'm not 100% sure why -n
is 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
希望能帮助到你