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

发布于 2024-08-09 17:13:45 字数 305 浏览 3 评论 0原文

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

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

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

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

如何获取尾部进程的PID?

I am trying to implement a simple log server in Bash. It should take a file as a parameter and serve it on a port with netcat.

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

But the problem is that when the netcat terminates, tail is left behind running. (Clarification: If I don't fork the tail process it will continue to run forever even the netcat terminates.)

If I somehow know the PID of the tail then I could kill it afterwards.
Obviously, using $! will return the PID of netcat.

How can I get the PID of the tail process?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

梦在深巷 2024-08-16 17:13:46

怎么样:

jobs -x echo %1

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

how about this:

jobs -x echo %1

%1 is for first job in chain, %2 for second, etc. jobs -x replaces job specifier with PID.

少年亿悲伤 2024-08-16 17:13:46

这对我有用(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 的想法代码>.

This works for me (SLES Linux):

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

The ps|grep|kill trick mentioned in this thread would not work if a user can run the script for two "instances" on the same machine.

jobs -x echo %1 did not work for me (man page not having the -x flag) but gave me the idea to try jobs -p.

一紙繁鸢 2024-08-16 17:13:46

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

Maybe you could use a fifo, so that you can capture the pid of the first process, e.g.:

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
梦回梦里 2024-08-16 17:13:46

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

我已经使用 ps 从 args 中 grep tail 并杀死它。这是一种黑客行为,但它确实有效。 :)

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

这是完整的脚本:
(最新版本可以在这里找到:http://docs.karamatli.com/dotfiles/bin/日志服务器)

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

Finally, I have managed to find the tail process using ps. Thanks to the idea from ennuikiller.

I have used the ps to grep tail from the args and kill it. It is kind of a hack but it worked. :)

If you can find a better way please share.

Here is the complete script:
(Latest version can be found here: 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
剑心龙吟 2024-08-16 17:13:46

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

ncat automatically terminates tail -f on exit (on 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
樱花细雨 2024-08-16 17:13:46

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

One way would be to simply do a ps -ef and grep for tail with your script ppid

我还不会笑 2024-08-16 17:13:46

您是否尝试过:(

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

未经测试)

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

Have you tried:

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

(untested)

Or -e with a scriptfile if your nc doesn't have -c. You may have to have an nc that was compiled with the GAPING_SECURITY_HOLE option. Yes, you should infer appropriate caveats from that option name.

那支青花 2024-08-16 17:13:46

您可以仅使用 Bash I/O 重定向将 tail 命令的 pid 存储在变量中(请参阅 如何获取管道中进程的 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

You may store the pid of the tail command in a variable using Bash I/O redirections only (see 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
风蛊 2024-08-16 17:13:46

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

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

Not an ideal answer, but I found a workaround for a logger daemon I worked on:

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

from $info tail:

--pid=PID
          with -f, terminate after process ID, PID dies
飘落散花 2024-08-16 17:13:46

您可以使用 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() 一样。

You could use the coproc command twice.

The given example translates to:

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"

(I've thrown a -v and a couple echo in there for troubleshooting.)

Using coproc feels a lot like using Popen() in various other scripting languages.

挽手叙旧 2024-08-16 17:13:46

bobbogo 答案可以工作,但需要中间pid文件

您可以利用进程替换功能>() 其工作方式类似于 | 但无需等待 tail 完成

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

bobbogo answer works but requires a intermediary pid file.

You can leverage the process substitution feature >() which works like| but without waiting for tail to finish

tail -f $1 > >(nc -l -p 9977) & pid=!
染柒℉ 2024-08-16 17:13:46

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

The --pid option to tail is your best friend here. It will allow you total control of the pipeline running in background. read the tail command options for more resilience in case your file is actively rotated by another process which might leave you tailing a inactive inode. The example below, though not used to process the data demonstrate the "imposed" restriction on the tail and the ability to tell it to exit at any time. This is used for measuring the service pressure on 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
薄凉少年不暖心 2024-08-16 17:13:45

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

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

Another option: use a redirect to subshell. This changes the order in which background processes are started, so $! gives PID of the tail process.

tail -f $1 > >(nc -l -p 9977) &
wait $!
属性 2024-08-16 17:13:45

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

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

Write tail's PID to file descriptor 3, and then capture it from there.

( tail -f $1 & echo $! >&3 ) 3>pid | nc -l -p 9977
kill $(<pid)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文