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を取得するにはどうすればよいですか

役に立ちましたか?

解決

ファイル記述子3にテールのPIDを書き込み、そこからキャプチャします。

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

他のヒント

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

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

これについてはどうですか:

jobs -x echo %1

%1 はチェーン内の最初のジョブ用、%2 は2番目用などです。 jobs -x はジョブ指定子をPIDに置き換えます。

これは私のために動作します(SLES Linux):

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

このスレッドで説明した ps | grep | kill のトリックは、ユーザーが2つの「インスタンス」に対してスクリプトを実行できる場合は機能しません。同じマシン上で。

jobs -x echo%1 は機能しませんでした(manページに -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 tailを削除しました。それは一種のハックですが、うまくいきました。 :)

より良い方法を見つけられる場合は、共有してください。

完全なスクリプトは次のとおりです。
(最新バージョンは、 http://docs.karamatli.com/dotfiles/bin/にあります。ログサーバー

if [ -z "$1" ]; then
    echo Usage: <*> 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

1つの方法は、スクリプトppidでtailにps -efとgrepを実行することです

試してみました:

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

(テストなし)

nc -c がない場合は、

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

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

理想的な答えではありませんが、私が取り組んでいたロガーデーモンの回避策を見つけました:

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

$ infoテールから:

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

tailの--pidオプションは、ここでの親友です。バックグラウンドで実行されているパイプラインを完全に制御できます。ファイルが別のプロセスによってアクティブにローテーションされ、非アクティブなiノードがテーリングされたままになった場合の復元力を高めるために、テールコマンドオプションをお読みください。以下の例は、データの処理には使用されていませんが、「面付け」を示しています。尾の制限と、いつでも終了するように指示する機能。これは、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 コマンドを2回使用できます。

指定された例は次のように変換されます:

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