我遇到的问题非常具体:
我有一个脚本无限期地浏览服务器列表,并在每个脚本上执行自身的副本(带有特定的参数集)。应捕获远程脚本stdout
以及执行它所花费的时间。这是一个非常简单的例子:
export TIMEFORMAT="%0E seconds"
server1=localhost
index=1
if [ "$1" != "" ]
then
cd /home
mv -n test _test &>/dev/null
sleep 10
echo $1
mv -n _test test &>/dev/null
else
i=0
while [ $i -lt $index ]
do
((i++))
server="server$i"
time=/tmp/time
echo "${!server} is doing stuff..."
result=$((time ssh ${!server} "$(basename $0) argument" 2>/dev/null </dev/null) 2>$time)
echo "Done in $(<$time), the result is $result"
rm $time
done
fi
因此,如果脚本收到一个参数,它会在本地执行(例如,重命名文件并在10秒内不执行任何操作);否则,它循环遍历服务器列表(例如,列表中只有一个服务器)并在远程主机上调用自身。 2>$time
将time
的stderr捕获到一个文件中,2>/dev/null
让错误保持安静,</dev/null
阻止ssh
窃取stdin
,所以它可以安全地在循环中运行。
问题是,当用户使用ctrl+c
终止脚本时,脚本的副本应该仍然优雅地终止在远程主机上(即文件重命名为初始名称),但事实并非如此。在没有循环的情况下做同样的事情很好 - 用户终止脚本,远程拷贝仍在运行并且优雅地结束,用户只是没有看到输出,这很好。我的理论是,问题与ssh
处于循环中有关,</dev/null
阻止它窃取stdin
,但我想不出绕过这个的方法。任何建议都非常感谢。
答案 0 :(得分:0)
user2303197的建议非常有意义 - 使远程脚本免受挂断信号的影响,但不幸的是,它不会影响脚本的行为。但是这个建议激发了我完全相反 - nohup
ssh调用,如下所示:
result=$((time nohup ssh ${!server} "$(basename $0) argument" & 2>/dev/null </dev/null) 2>$time)
它使ssh不受ctrl+c
的影响,但它会在它完成后立即打破它运行的循环,这正是我需要它做的。
编辑: 经过一周的测试,结果发现这个脚本没有按照我的意愿执行。删除与远程主机的连接后,远程脚本不会正常结束。有任何建议如何解决这个问题?