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

StackOverflow https://stackoverflow.com/questions/1652680

  •  22-07-2019
  •  | 
  •  

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

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

但问题是,当 netcat 终止时,tail 仍然在运行。(澄清:如果我不分叉尾部进程,即使 netcat 终止,它也会继续永远运行。)

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

如何获取尾部进程的PID?

有帮助吗?

解决方案

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

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

其他提示

另一种选择:使用重定向到子shell。这将更改在后台进程正在启动,因此$订购!给出tail过程的PID。

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

这个怎么样:

jobs -x echo %1

%1为在链的第一个工作,对%2第二等jobs -x替换作业说明符PID。

这对我的作品(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

也许你可以使用 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

最后,我已成功地找到使用ps尾过程。由于从ennuikiller的想法。

我已经使用了ps从ARGS grep的尾部和杀死它。这是怎样的一个黑客,但它的工作。 :)

如果你能找到一个更好的办法,请分享。

下面是完整的脚本:点击 (最新版本可以在这里找到: 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

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

一个方法是简单地做尾PS -ef和grep与你的脚本PPID

你试过:

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

(未测试的)

或者用脚本文件-e如果您nc没有-c。您可能需要有一个是与nc选项编译的GAPING_SECURITY_HOLE。是的,你应该从选项名称推断出相应的注意事项。

您可以存储 pid tail 仅使用 Bash I/O 重定向的变量中的命令(请参阅 如何获取管道中进程的PID).

# 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

不是一个理想的答案,但我发现一个日志守护进程,我曾在一个解决方法:

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

从$信息尾:

--pid=PID
          with -f, terminate after process ID, PID dies

在--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"

(我已经抛出-v,并在那里进行故障排除一对夫妇echo。)

使用coproc感觉很像在各种其它脚本语言使用POPEN()。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top