后台作业从脚本运行时终止,但从bash提示符运行时工作正常

我在MacOS 10.9.4上。 如下所示,我想把sftp放到后台,以后通过命名pipe道自动将一些文件推送到它。 当我从bash提示符手动input命令(使用cat作为侦听器作业以简化)时,它工作正常:

  $ mkfifo test $ cat > test & [1] 60765 $ cat test | cat & [2] 60781 60782 [1] + 60765 suspended (tty input) cat > test $ echo works! > test works! $ ps -ax | grep 60765 60765 ttys023 0:00.00 cat 60900 ttys023 0:00.00 grep 60765 

但是,当我把它放在bash脚本中停止工作:

  $ cat test.sh mkfifo test1 cat > test1 & echo $! cat test1 | cat & $ bash test.sh 60847 $ echo fails > test1 ^C% $ ps -ax | grep 60847 60882 ttys023 0:00.00 grep 60847 

这里的问题,据我所知,是cat > test1 &线从提示运行时工作正常,但以某种方式从脚本运行时终止,所以我的侦听器作业收到EOF并终止。

我在这里错过了什么,我怎样才能使这从脚本工作?

编辑:我面临的实际问题是这样的。 为了开发,我必须将代码部署到远程服务器。 为此,我使用了rsync,并自动化了这一点,我使用fswatch来监听文件夹中的文件更改,并在发生更改时运行rsync。

  $ fswatch -0 . | while read -d "" event; do rsync ./ {remote folder} done 

它工作正常,直到我试图使用它在慢延迟大连接。 每次Rsync打开新的SSH连接,并发现文件的差异,这需要时间慢连接。 我试图解决这个问题,打开与sftp的持久连接,并推动它只改变文件,我从fswatch收到的名字。 为了这个工作,我需要一种方法来启动sftp进程,稍后发送fswatch事件时发送命令。 我发现这个问题,但写入/ proc / {pid} / fd / 0并不假设在mac上工作,所以我试图使用命名pipe道的答案。 在启动fswatch脚本之前,我可以运行cat > test1 &手动,所以这实际上是可行的。 但我想要一个可靠的解决scheme,能够把这个脚本给我的同事。

所有这些与后台进程尝试从terminal读取时发生的事情有关。 默认情况下只允许活动进程组从terminal读取。 如果活动进程组以外的进程尝试从terminal读取数据,则会发送一个信号暂停该进程,直到被shell唤醒。

在你的第一个例子中,你正在启动两个进程组。 每个都在后台启动,因此都不允许从terminal读取。

cat > test &会立即尝试从terminal读取并暂停。 但是,只有在显示下一个提示之前,您才会通过bash通知您,因此您必须在通知之前键入另一个命令。

您的echo命令将写入由第二个进程组(未暂停)读取的pipe道。 在这个序列的最后,第一个cat命令保持暂停状态,不会再被唤醒。

在第二个示例中,整个脚本运行在一个进程组中。 所以在这一点上,在进程组中有三个不同的cat命令,其中一个在从terminal读取时被阻塞。 然后你返回到最初的bash shell,这样线程组必须被挂起。

而且从你最初的bash shell的angular度来看,这个线程组已经被终止了,因为它看到了你input的第二个bash命令。 最初的bash shell并不知道subprocess产生了大孩子,而其中一个被阻塞在terminal读取。

当脚本的进程组不再受初始bash shell的控制时,第一个cat命令将在其input上得到EOF。 此时所有的cat命令都会看到空的input并立即完成处理。