(bash) 脚本 A,等待脚本 B,但不等待其子进程

(bash) 脚本 A,等待脚本 B,但不等待其子进程

所以我有 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__endslept稍后显示在后台。ssh

答案4

你可以试试这个。$!是默认的 shell 变量,包含最近执行的后台管道/进程的进程 ID。

command1 &
lpid1=$!

command2 &
lpid2=$!

command3 &
lpid=$!

wait $lpid1  # waits for only the process with PID lpid1  to complete. 

您需要根据您的脚本使用export变量等来利用它

相关内容