所以我有 scriptA ,它的作用是:
ssh server1 -- scriptB &
ssh server2 -- scriptB &
ssh server3 -- scriptB &
wait
otherstuffhappens
ScriptB 的作用是:
rsync -av /important/stuff/. remoteserver:/remote/dir/.
rsync -av /not/so/important/stuff/. remoteserver:/remote/dir/. &
exit
我想要的结果是 scriptA 将等待 scriptB 的所有实例完成后再继续,目前它正在这样做,但它也在等待不那么重要的东西的后台 rsync。这些文件较大,我不想等待。
我已读完nohup、disown 和 & 之间的区别并尝试了不同的组合,但我没有得到我想要的结果。
在这一点上我很困惑。任何帮助,将不胜感激!
答案1
这里的问题是sshd
等待管道上的文件结尾,它正在读取命令的标准输出(由于某种原因而不是标准错误,至少对于我正在测试的版本)。并且后台作业继承了该管道的 fd。
因此,要解决这个问题,请将后台命令的输出重定向rsync
到某个文件,或者/dev/null
如果您不关心它的话。您还应该重定向 stderr,因为即使 sshd 没有等待相应的管道,sshd
退出后,管道也会被破坏,因此rsync
如果它尝试在 stderr 上写入,就会被杀死。
所以:
rsync ... > /dev/null 2>&1 &
比较:
$ time ssh localhost 'sleep 2 &'
ssh localhost 'sleep 2 &' 0.05s user 0.00s system 2% cpu 2.365 total
$ time ssh localhost 'sleep 2 > /dev/null &'
ssh localhost 'sleep 2 > /dev/null &' 0.04s user 0.00s system 12% cpu 0.349 total
和:
$ ssh localhost '(sleep 1; ls /x; echo "$?" > out) > /dev/null &'; sleep 2; cat out
141 # ls by killed with SIGPIPE upon writing the error message
$ ssh localhost '(sleep 1; ls /x; echo "$?" > out) > /dev/null 2>&1 &'; sleep 2; cat out
2 # ls exited normally after writing the error on /dev/null instead
# of a broken pipe
答案2
编写一个脚本,它是两者的父脚本,然后你可以轻松地控制两者。或者在两个通道之间建立通信通道。
要专门忽略某些后台作业,您可以捕获 PID($!
是最后一个后台作业 PID)并wait $pid
仅等待该作业完成。
答案3
-f
用于ssh
修复问题的标志。测试于:
#!/bin/sh -e
echo $$_script__begin
( echo sleeping; sleep 2; echo slept )&
echo $$_script__end
当我使用 运行它时ssh localhost ./script
,它会等待直到slept
出现。使用该-f
标志,它会在命令返回后退出echo $$_script__end
并slept
稍后显示在后台。ssh
答案4
你可以试试这个。$!
是默认的 shell 变量,包含最近执行的后台管道/进程的进程 ID。
command1 &
lpid1=$!
command2 &
lpid2=$!
command3 &
lpid=$!
wait $lpid1 # waits for only the process with PID lpid1 to complete.
您需要根据您的脚本使用export
变量等来利用它