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

如何在Bash中获取通过管道传输到另一个进程的进程的PID?,bash,pipe,pid,Bash,Pipe,Pid,我试图在Bash中实现一个简单的日志服务器。它应该将一个文件作为参数,并在netcat的端口上提供该文件 ( tail -f $1 & ) | nc -l -p 9977 但问题是,当netcat终止时,tail就没有运行了。(澄清:如果我不分叉尾部进程,即使netcat终止,它也将永远运行。) 如果我知道尾巴的PID,我可以在事后杀死它。 显然,使用$!将返回netcat的PID 如何获取tail进程的PID?一种方法是简单地使用脚本ppid执行ps-ef和grep for tail

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

( tail -f $1 & ) | nc -l -p 9977
但问题是,当netcat终止时,tail就没有运行了。(澄清:如果我不分叉尾部进程,即使netcat终止,它也将永远运行。)

如果我知道尾巴的PID,我可以在事后杀死它。
显然,使用$!将返回netcat的PID


如何获取tail进程的PID?

一种方法是简单地使用脚本ppid执行ps-ef和grep for tail

也许您可以使用,以便捕获第一个进程的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
您是否尝试过:

nc -l -p 9977 -c "tail -f $1"
(未经测试)


或者如果您的
nc
没有
-c
,则使用脚本文件
-e
。您可能需要使用
GAPING\u SECURITY\u HOLE
选项编译一个
nc
。是的,您应该从该选项名称推断出适当的注意事项。

最后,我使用
ps
找到了尾部进程。多亏了ennuikiller的创意

我使用了
ps
从args中grep tail并杀死它。这有点像黑客,但它奏效了。:)

如果你能找到更好的方法,请分享

以下是完整的脚本:
(最新版本可在此处找到:)


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

( tail -f $1 & echo $! >&3 ) 3>pid | nc -l -p 9977
kill $(<pid)
(tail-f$1&echo$!>&3)3>pid | nc-l-p9977

kill$(
ncat
在退出时自动终止
tail-f
(在Mac OS X 10.6.7上)

#Bash中使用ncat的简单日志服务器
#比照。http://nmap.org/ncat/
touch file.log

ncat-l 9977-c“tail-f file.log”您可以仅使用Bash I/O重定向将
tail
命令的pid存储在变量中(请参阅)

#终端窗口1
#在Mac OS X上使用nc(FreeBSD nc)
:>/tmp/foo
PID=$({tail-f/tmp/foo 0&3;}4&1 | head-1)
杀死$PID
#终端窗口2
nc本地主机9977
#终端窗口3
回音线>/tmp/foo

另一个选项:使用重定向到subshell。这会更改后台进程的启动顺序,因此$!会给出
尾部进程的PID

tail -f $1 > >(nc -l -p 9977) &
wait $!
这个怎么样:

jobs -x echo %1

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

这不是一个理想的答案,但我找到了一个解决我使用的记录器守护程序的方法:

#!/bin/sh
tail -f /etc/service/rt4/log/main/current --pid=$$ | grep error
从$info tail开始:

--pid=PID
          with -f, terminate after process ID, PID dies
这适用于我(SLES Linux):

如果用户可以在同一台机器上为两个“实例”运行脚本,则此线程中提到的
ps | grep | kill
技巧将不起作用

作业-x echo%1对我不起作用(手册页没有
-x
标志)但是给了我一个尝试
jobs-p

tail的--pid选项是您最好的朋友。它将允许您完全控制后台运行的管道。如果您的文件被另一个进程主动旋转,可能导致您跟踪一个不活动的inode,请阅读tail命令选项以获得更大的恢复力。例如低,尽管不用于处理数据,但证明了尾部的“强制”限制以及随时告知其退出的能力。这用于测量httpd上的工作压力

  # Set the tail to die in 100 second even if we die unexpectedlly.
sleep 100 & ;  ctlpid=$!
tail -q -n 0 --follow=name --retry --max-unchanged-stats=1 --pid=$ctlpid -f  /var/log/httpd/access_log 2>/dev/null | wc –l > /tmp/thisSampleRate &
…. Do some other work
….  Can kill the pipe at any time by killing $ctlpid 
…. Calculate preassure if /tmp/thisSampleRate is ready

您可以使用
coproc
命令两次

给出的示例可转化为:

coproc TAIL { tail -f $1; }; exec {TAIL[1]}<&-
coproc NC { nc -v -l -p 9977; } <&"${TAIL[0]}" >&1
wait $NC_PID; echo "nc exit code: $!"
kill $TAIL_PID; echo "done"
coproc TAIL{TAIL-f$1;};exec{TAIL[1]}可以工作,但需要一个中介pid文件

您可以利用功能
>()
,它的工作原理类似于
|
,但无需等待
tail
完成

tail -f $1 > >(nc -l -p 9977) & pid=!

是的,我以前试过。使用fifo的问题是一样的:管道永远不会终止,所以即使netcat终止,cat也会保持运行。控件也会保持在cat行中,所以它永远不会执行kill。这很奇怪-上面的脚本在Mac OS X上对我非常有效。唯一的细微区别是我忽略了nc的“-p”标志。也许这是一个错误平台问题(关于如何处理管道)。我正在linux机器上尝试它。无论如何谢谢你的回答!如果你删除
cat
并使用
nc-l-p9977<$FIFO
?哦,我从来没有想过。我希望它能工作:),但它仍然没有终止,因为“tail-f”的性质如果没有-f,就可以了。但我想实时提供它。我无法使用ppid获取它,因为当我在子shell中分叉它时它是分离的。但是我设法使用
ps
程序的args参数grep它。tail命令的PID不应该在
$!
中可用,这样你就可以简单地执行
kill$!
关于
kill_tail
?我使用了一个变体:
(tail-f$1&echo$!>pid)| nc-l-p 9977
(不确定在最终重定向到文件时为什么使用文件描述符3会有帮助)不知道为什么,但我的解决方案在输出两行日志后失败。可能是在管道缓冲区已满时。然后初始进程似乎在等待管道被处理。如果不使用
&
,会发生什么情况?
tail-f
应该在那里等待。我不知道
&
是用于什么,尽管它确实在那里这是一个更大的脚本的一部分。无论如何,如果你杀死了管道,我会认为尾巴会死(只要你没有背景)。根据我对shell的理解,在这个例子中,它的意思是“开始到背景”。至少,这是我现在看到的行为,试图将解决方案应用于我自己的类似问题。相关:此方法的优点是,在等待之后,$?还保持退出状态。这似乎是最干净的方法。它会改变什么(与标准管道相比)从启动顺序以外的任何一个进程的角度来看,实际上,重定向的语法是错误的(尽管
tail -F xxxx | tee -a yyyy &
export TAIL_PID=`jobs -p`
# export TEE_PID="$!"
  # Set the tail to die in 100 second even if we die unexpectedlly.
sleep 100 & ;  ctlpid=$!
tail -q -n 0 --follow=name --retry --max-unchanged-stats=1 --pid=$ctlpid -f  /var/log/httpd/access_log 2>/dev/null | wc –l > /tmp/thisSampleRate &
…. Do some other work
….  Can kill the pipe at any time by killing $ctlpid 
…. Calculate preassure if /tmp/thisSampleRate is ready
coproc TAIL { tail -f $1; }; exec {TAIL[1]}<&-
coproc NC { nc -v -l -p 9977; } <&"${TAIL[0]}" >&1
wait $NC_PID; echo "nc exit code: $!"
kill $TAIL_PID; echo "done"
tail -f $1 > >(nc -l -p 9977) & pid=!