2009-10-30 11 views
37

私はBashで単純なログサーバーを実装しようとしています。それはパラメータとしてファイルをとり、netcatでポート上で提供する必要があります。Bashの別のプロセスにパイプされるプロセスのPIDを取得するには?

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

しかし、問題は、netcatが終了すると、tailが実行中に残っていることです。 (明確化:もし私がtailプロセスをフォークしなければ、netcatが終了しても永遠に走り続けるだろう)

私は何とかテールのPIDを知っていれば、後でそれを殺すことができます。
明らかに、$! netcatのPIDを返します。

テールプロセスのPIDを取得するにはどうすればよいですか?

+0

「&」を使用しないとどうなりますか? 'tail -f'はちょうどそこで待つことになっています。私は '&'が何を得ているのか分かりませんが、これはもっと大きなスクリプトの一部であるように見えます。とにかく、あなたがパイプを殺すと、私はテールが死ぬと思うでしょう(あなたがそれをバックグラウンドにしていない限り)。 –

+0

私の貝殻の理解から、&この場合には、その意味で "バックグラウンドを開始"として使用されています。少なくとも、それは今私が見ている動作で、私自身の同様の問題に解決策を適用しようとしています。 – starturtle

答えて

27

ライトテールのPIDここで

は完全なスクリプトです。

(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

+0

なぜか分かりませんが、いくつかのログ行が出力された後に私の解決策が失敗します。おそらく、パイプバッファがいっぱいになったときです。その後、最初のプロセスはパイプが処理されるのを待っているようです。 – Wernight

1

一つの方法は、例えば、あなたが最初のプロセスのPIDを取り込むことができるように、単にスクリプトのPPID

+0

サブシェルでフォークしたときにデタッチされるので、ppidを使って取得できませんでした。しかし、私は 'ps'プログラムの引数paramを使ってgrepを管理しました。 –

6

と尾のためのps -efとgrepを行うたぶんあなたは、fifoを使用することができますし、次のようになります。

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を使うことに関する問題は同じです:パイプは決して終了しないので、catはnetcatを終了しても実行し続けます。また、コントロールはcat行にとどまり、killを実行しません。 –

+0

これは奇妙です - 上記のスクリプトはMac OS Xで私にとって完璧に働きました。ちょっとした違いは、ncの '-p'フラグを省略したことだけでした。 –

+0

おそらくそのプラットフォームの問題(パイプの扱い方について)です。私はLinuxマシンでそれを試しています。とにかくあなたの答えをありがとう! –

1

あなたが試してみました:

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

(未テスト)

nc-cがない場合は、-eにスクリプトファイルを指定してください。 GAPING_SECURITY_HOLEオプションでコンパイルされたncが必要な場合があります。はい、そのオプション名から適切な警告を推論する必要があります。

+0

ああ、私はそれを考えなかった。私はそれがうまくいってほしい:) しかし、それは "テール-f"の性質のためにまだ終了していません –

+0

'-f'なしでどうなりますか? –

+0

は-fなしでOKです。しかし、私はリアルタイムでそれを提供したい。 –

2

最後に、psを使用してテールプロセスを見つけることができました。 ennuikillerからのアイデアのおかげで。

私は、psを使ってargsからgrep tailを作成し、それを削除しました。それはハックのようなものですが、うまくいきました。 :)

より良い方法を見つけることができる場合は、共有してください。
(最新版はここで見つけることができます:http://docs.karamatli.com/dotfiles/bin/logserver)記述子3を提出した後、そこからそれをキャプチャする

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_tail'ではなく' kill $! ' – tripleee

2

ncat自動的には(Mac OS X 10.6.7上で)終了時にtail -fを終了!

# 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

あなただけのバッシュ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 
28

別のオプション:サブシェルにリダイレクトします。これにより、バックグラウンドプロセスの開始順序が変更されるので、$! tailプロセスのPIDを返します。これについて

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

このアプローチの利点は、待ってから、$?また、終了ステータスを保持します –

+0

これはロングショットで最もクリーンなアプローチのようです。開始順序以外のプロセスの観点から(標準配管と比較して)何かを変更しますか? – wlritchi

+8

実際、そのリダイレクトの構文は間違っています(原則は正しいが)。 '>(foo)'は新しいファイル記述子の名前に置き換えられ、 '>(foo)'は実際に出力をそのファイルにリダイレクトします。最初の行を 'tail -f $ 1>>(nc -l -p 9977)&'にしたいとします。 – wlritchi

9

方法:

jobs -x echo %1 

%1jobs -xはPIDでジョブ指定子を置き換えるなど、チェーン内の最初の仕事のために第二のため%2です。

+1

これは、「チェーン内のどのプロセスでもpidを取得するには」最もクリーンで最短のソリューションでなければなりません。ありがとうございました!これはバックグラウンドで実行されているチェーンの中で、プロセスのPIDを早く取得する '&'とも機能します!例えば。 'dd if =/dev/urandom bs = 1M count = 1024 | sha1sum&pid = $(jobs - x echo%1) ' ' kill -USR1 $ pid' – JATothrim

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トリックは動作しません同じマシン上に2つの「インスタンス」があります。

jobs -x echo %1私のためには機能しませんでしたが(マニュアルページには-xフラグがありません)、私にはjobs -pを試してみてください。

0

tailに--pidオプションは、ここであなたの親友です。バックグラウンドで実行されているパイプラインを完全に制御することができます。あなたのファイルが積極的に別のプロセスによってローテートされていて、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 
関連する問題