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

时间:2009-10-30 22:43:22

标签: bash pipe pid

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

( tail -f $1 & ) | nc -l -p 9977

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

如果我以某种方式知道尾部的PID,那么我可以在之后杀死它 显然,使用$!将返回netcat的PID。

如何获得尾部过程的PID?

14 个答案:

答案 0 :(得分:35)

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

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

答案 1 :(得分:35)

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

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

答案 2 :(得分:13)

怎么样:

jobs -x echo %1

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

答案 3 :(得分:9)

这对我有用(SLES Linux):

tail -F xxxx | tee -a yyyy &
export TAIL_PID=`jobs -p`
# export TEE_PID="$!"

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

jobs -x echo %1对我不起作用(手册页没有-x标志),但让我尝试jobs -p

答案 4 :(得分: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

答案 5 :(得分:2)

最后,我设法使用ps找到了尾部流程。感谢ennuikiller的想法。

我已经使用ps从args中获取尾巴并将其杀死。它有点像黑客但它有效。 :)

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

这是完整的脚本:
(最新版本可在此处找到:http://docs.karamatli.com/dotfiles/bin/logserver

if [ -z "$1" ]; then
    echo Usage: $0 LOGFILE [PORT]
    exit -1
fi
if [ -n "$2" ]; then
    PORT=$2
else
    PORT=9977
fi

TAIL_CMD="tail -f $1"

function kill_tail {
    # find and kill the tail process that is detached from the current process
    TAIL_PID=$(/bin/ps -eo pid,args | grep "$TAIL_CMD" | grep -v grep | awk '{ print $1 }')
    kill $TAIL_PID
}
trap "kill_tail; exit 0" SIGINT SIGTERM

while true; do
    ( $TAIL_CMD & ) | nc -l -p $PORT -vvv
    kill_tail
done

答案 6 :(得分:2)

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

# simple log server in Bash using ncat
# cf. http://nmap.org/ncat/
touch file.log
ncat -l 9977 -c "tail -f file.log" </dev/null   # terminal window 1
ncat localhost 9977 </dev/null                  # terminal window 2
echo hello > file.log                           # terminal window 3

答案 7 :(得分:1)

一种方法是用你的脚本ppid

简单地做一个ps -ef和grep for tail

答案 8 :(得分:1)

你试过了吗?

nc -l -p 9977 -c "tail -f $1"

(未测试的)

如果您的-e没有nc,请使用脚本文件-c。您可能必须使用nc选项编译GAPING_SECURITY_HOLE。是的,您应该从该选项名称中推断出适当的警告。

答案 9 :(得分:1)

您可以仅使用Bash I / O重定向将tail命令的pid存储在变量中(请参阅How to get the PID of a process in a pipeline)。

# terminal window 1
# using nc on Mac OS X (FreeBSD nc)
: > /tmp/foo
PID=$( { { tail -f /tmp/foo 0<&4 & echo $! >&3 ; } 4<&0 | { nc -l 9977 ;} & } 3>&1 | head -1 )
kill $PID

# terminal window 2
nc localhost 9977

# terminal window 3
echo line > /tmp/foo

答案 10 :(得分:0)

不是一个理想的答案,但我找到了我工作的logger守护程序的解决方法:

#!/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

答案 11 :(得分:0)

尾巴的--pid选项是你最好的朋友。它将允许您完全控制在后台运行的管道。读取tail命令选项以获得更大的弹性,以防您的文件被另一个进程主动轮换,这可能会让您拖尾一个非活动的inode。下面的示例虽然不用于处理数据,但可以证明&#34;强加的&#34;对尾巴的限制以及随时告诉它退出的能力。这用于测量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

答案 12 :(得分:0)

您可以两次使用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"

(我在其中丢了一个-v和几个echo以进行故障排除。)

使用coproc就像在其他各种脚本语言中使用Popen()一样。

答案 13 :(得分:0)

bobbogo answer有效,但需要中介 pid文件

您可以利用>()的{​​{3}}功能|,但不必等待tail完成

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