2009-10-30 140 views
37

我想在Bash中實現一個簡單的日誌服務器。它應該將一個文件作爲參數並通過netcat在端口上提供。如何獲取一個進程在Bash中的另一個進程的PID?

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

但問題是,當netcat終止時,尾部留下運行。 (澄清:如果我不分叉尾部進程,它將繼續運行,即使netcat終止。)

如果我以某種方式知道尾部的PID,那麼我可以在之後殺死它。
顯然,使用$!將返回netcat的PID。

如何獲得尾部過程的PID?

+0

如果不使用'&'會怎麼樣? 'tail -f'應該等在那裏。我不明白''是什麼,儘管它看起來像是一個更大腳本的一部分。無論如何,如果你殺了菸斗,我會認爲尾巴會死(只要你沒有背景)。 – 2013-05-22 05:11:21

+0

來自我對殼的理解,在這種情況下,它的含義是「從開始到背景」。至少,這就是我現在看到的行爲,試圖將解決方案應用於我自己的類似問題。 – starturtle 2016-07-07 11:02:16

回答

27

寫尾巴的PID文件描述符3,然後從那裏捕捉到它。

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

我使用了一個變體:'(tail -f $ 1&echo $!> pid)| nc -l -p 9977'(不知道爲什麼使用文件描述符3在最終重定向到文件時會有所幫助) – Wernight 2012-02-06 16:19:44

+0

不知道爲什麼,但是在輸出幾個日誌行後,我的解決方案失敗。可能在管道緩衝區已滿時。然後,初始過程似乎在等待管道被處理。 – Wernight 2012-02-07 10:54:11

1

一種方法是簡單地做尾PS -ef和grep與你的腳本PPID

+0

我無法使用ppid獲取它,因爲當我將它分叉到子殼中時它會分離。但我設法使用'ps'程序的參數param來對其進行grep。 – 2009-10-31 12:02:00

6

也許你可以使用一個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 
+0

是的,我曾嘗試過。關於使用fifo的問題是相同的:管道永遠不會終止,因此即使netcat終止,cat仍然運行。此外,控制停留在貓行,所以它從不執行殺死。 – 2009-10-31 09:25:30

+0

這很奇怪 - 上面的腳本在Mac OS X上完全適用於我。只是略有不同,我省略了'-p'標誌。 – 2009-10-31 10:06:04

+0

也許它是一個平臺問題(關於如何處理管道)。我正在linux機器上嘗試它。無論如何感謝您的回答! – 2009-10-31 10:17:04

1

你試過:

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

(未經測試)

-e與腳本文件如果您的nc沒有-c。您可能必須具有使用GAPING_SECURITY_HOLE選項編譯的nc。是的,你應該從該選項名稱推斷出適當的警告。

+0

哦,我從來沒有想過它。我希望它的工作:) 但它仍然沒有終止,因爲「tail -f」的性質 – 2009-10-31 10:19:51

+0

沒有'-f'怎麼辦?沒有-f, – 2009-10-31 10:27:52

+0

。但我想實時提供服務。 – 2009-10-31 10:36:55

2

最後,我設法找到使用ps的尾部過程。感謝ennuikiller的想法。

我已經使用了ps grep尾巴從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 
+0

不應該在'$!'中使用tail命令的PID,以便您可以簡單地執行kill $!而不是kill_tail? – tripleee 2011-09-19 09:30:46

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 
1

您可能使用bash I/O重定向只(見How to get the PID of a process in a pipeline)存儲tail命令的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 
28

另一種選擇:使用重定向到subshel​​l。這改變了後臺進程開始的順序,所以$!給出了tail進程的PID。

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

這種方法的優點是等待後,$?也持有退出狀態 – 2013-12-13 18:00:45

+0

這似乎是一個長鏡頭最清潔的方法。從開始訂單以外的其他流程的角度來看,它是否會改變任何事情(與標準管道相比)? – wlritchi 2014-09-07 05:54:54

+8

實際上,重定向的語法是錯誤的(儘管原理是正確的)。 '>(foo)'替換新文件描述符的名稱,而'>>(foo)'實際上將輸出重定向到它。你希望第一行是'tail -f $ 1 >>>(nc -l -p 9977)&'。 – wlritchi 2014-09-07 06:27:28

9

這個怎麼樣:

jobs -x echo %1 

%1是在鏈的第一份工作,%2爲第二等jobs -x替換工作說明符PID。

+1

這必須是「如何在鏈中更早獲得任何進程的PID」的最簡潔+最短的解決方案。謝謝!它也適用於'&'在後臺運行的鏈中獲取進程的pid!例如。 'dd if =/dev/urandom bs = 1M count = 1024 | sha1sum&pid = $(jobs - x echo%1)' 'kill -USR1 $ pid' – JATothrim 2014-11-29 12:05:32

0

不是一個理想的答案,但我發現一個日誌守護進程,我在工作了解決方法:

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

從$信息尾:

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

這對我的作品(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

0

尾巴的--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