我正在尝试在Bash中实现一个简单的日志服务器。它应该将文件作为参数并在具有netcat的端口上提供。
( tail -f $1 & ) | nc -l -p 9977
但问题是当netcat终止时,tail会被遗忘。 (澄清:如果我不分叉尾程,它将继续运行,即使netcat终止。)
如果我以某种方式知道尾部的PID,那么我可以在之后杀死它 显然,使用$!将返回netcat的PID。
如何获得尾部过程的PID?
答案 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)