如何获取在Bash中通过管道传输给另一个进程的进程的PID?

Ert*_*tlı 51 bash pid pipe

我试图在Bash中实现一个简单的日志服务器.它应该将文件作为参数并在具有netcat的端口上提供.

( tail -f $1 & ) | nc -l -p 9977
Run Code Online (Sandbox Code Playgroud)

但问题是当netcat终止时,尾巴会被遗忘.(澄清:如果我不分叉尾程,它将继续运行,即使netcat终止.)

如果我以某种方式知道尾巴的PID然后我可以杀死它.
显然,使用$!将返回netcat的PID.

如何获得尾部过程的PID?

Vla*_*adV 39

另一种选择:使用重定向到子shell.这会改变后台进程的启动顺序,所以$!给出tail过程的PID .

tail -f $1 > >(nc -l -p 9977) &
wait $!
Run Code Online (Sandbox Code Playgroud)

  • 实际上,该重定向的语法是错误的(尽管原理是正确的).`>(foo)`代替新文件描述符的名称,而`>>(foo)`实际上将输出重定向到它.你希望第一行是`tail -f $ 1 >>(nc -l -p 9977)&`. (8认同)

小智 38

将尾部的PID写入文件描述符3,然后从那里捕获它.

( tail -f $1 & echo $! >&3 ) 3>pid | nc -l -p 9977
kill $(<pid)
Run Code Online (Sandbox Code Playgroud)

  • 我使用了一个变体:`(tail -f $ 1&echo $!> pid)| nc -l -p 9977`(不确定为什么在最终重定向到文件时使用文件描述符3会有所帮助) (5认同)

小智 15

这个怎么样:

jobs -x echo %1
Run Code Online (Sandbox Code Playgroud)

%1用于链中的第一个作业,%2用于第二个等等jobs -x.用PID替换作业说明符.

  • 答案是错误的。对于整个管道,仅分配一个作业 ID:`shopt -s lastpipe; 睡眠 1 | 猫 | 作业` -&gt; `[1] 运行睡眠 1 | 猫`。它具有管道上第一个命令的 PID,但“jobs -l”会打印所有 PID:“shopt -s lastpipe;” 睡眠 1 | 猫 | 工作-l;作业 -p` -&gt; `[1] 5394 运行睡眠 1` `5395 | 猫``5394`。 (3认同)
  • 这一定是“如何获取链中较早的任何进程的 pid”的最干净+最短的解决方案,谢谢!它还可以与“&amp;”一起使用,获取后台运行的链中较早进程的 pid!例如 `dd if=/dev/urandom bs=1M count=1024 | sha1sum &amp; pid=$(jobs - x echo %1)` `kill -USR1 $pid` (2认同)

小智 9

这对我有用(SLES Linux):

tail -F xxxx | tee -a yyyy &
export TAIL_PID=`jobs -p`
# export TEE_PID="$!"
Run Code Online (Sandbox Code Playgroud)

ps|grep|kill如果用户可以在同一台机器上运行两个"实例"的脚本,则此线程中提到的技巧将无效.

jobs -x echo %1没有为我工作(手册页没有-x标志),但给了我尝试的想法jobs -p.


mar*_*ton 7

也许你可以使用fifo,这样你就可以捕获第一个进程的pid,例如:

FIFO=my_fifo

rm -f $FIFO
mkfifo $FIFO

tail -f $1 > $FIFO &
TAIL_PID=$!

cat $FIFO | nc -l -p 9977

kill $TAIL_PID

rm -f $FIFO
Run Code Online (Sandbox Code Playgroud)