命令替换($(...))强制进程前台运行

12

摘要: 我有一个Bash脚本,它在后台运行进程,并且应该像正常命令一样工作,也可以在命令替代块中使用,例如$(...)。脚本本身会生成一个分支到后台的进程。可以将其简化为此测试案例:

#!/bin/sh
echo something
sleep 5 &

在shell中运行此脚本将立即返回(并打印“something”),在 $(...) 内部运行它将挂起5秒钟,等待后台的“sleep”完成。

适用于在命令替换shell内启动并在后台产生进程的任何内容,包括该进程树中的任何子进程。似乎影响bash和zsh,尚未尝试其他Shell。


原始问题:我有一个bash脚本,每次运行时都应该将一个值输出到stdout,并将其复制到X剪贴板中。

#!/bin/sh
echo something
echo something | xclip -selection clipboard

这个脚本(我们称之为“something”)旨在用于获取此单词(实际上是另一个命令的输出),并以不同的方式使用,例如:

$ something
something
$ xclip -o -selection clipboard
something
$ echo $(something)
^C

向标准输出打印内容,将输出复制到剪贴板中以在常规X应用程序中使用,并且也应该能够使用Bash命令替换将标准输出插入到任何命令的中间。

但是,Bash命令替换似乎强制xclip保持在前台运行。由于X剪贴板要求客户端提供剪贴板内容,因此xclip通常会将自己设为守护进程,并且默认行为是一旦剪贴板内容被替换就退出。

在遇到xclip的问题后,我编写了本问题开头的最小测试用例,因此似乎适用于在$(...)Shell中内部设置为守护进程的任何内容。

有人可以解释这种行为吗?有没有办法避免它?

1个回答

18

如果你希望后台进程不影响命令替换,你需要断开它的标准输出。这将立即返回:

如果您想让后台进程不干扰命令替换,您需要断开其stdout连接。这将立即返回:

$ cat bg.sh 
#!/bin/sh
echo before
sleep 5 >/dev/null &
echo after
$ date; x=$(./bg.sh); date; echo "$x"
Sat Jun  1 13:02:26 EDT 2013
Sat Jun  1 13:02:26 EDT 2013
before
after

如果你将进程放到后台运行,就会失去捕获后台进程的标准输出的能力,但是如果你在后台运行它,你可能并不关心这个。 bg.sh 进程总是可以写入磁盘的。


哇!完美而且非常简单的解决方案。谢谢! - dequis
1
顺便提一下,将输出重定向到文件而不是 /dev/null 似乎可以捕获输出,但至少在这里,输出文件似乎只有在后台进程退出后才会更新。(虽然我不需要它) - dequis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接