LoginSignup
0
1

More than 1 year has passed since last update.

パイプで繋がったコマンドをバックグラウンドで実行した際に、最初のプロセスのプロセスIDを取得する

Posted at

シェルにおいて、バックグラウンド実行のプロセスIDは$!で取得することができる。

sleep 10 &
echo $!          # sleepコマンドのプロセスIDが取得できる。

では、コマンドがパイプで繋がれている場合はどうなるだろうか?

tail -f log.txt | grep 'keyword' &
echo $!

この場合、$!で取得されるのは、パイプの後半のプロセスgrepコマンドのプロセスになる。

ここで問題となるのはkill $!として、grepをキルしてもtailのプロセスが残ってしまうことである。

$ kill $!       # grepのみがキルされる
$ ps aux | grep tail            # tailのプロセスがまだ残っている
# >  9210   0.0  0.0 34122900    900 s000  SN    6:17PM   0:00.00 tail -f log.txt

前半のプロセスのプロセスIDを取得するにはどうすれば良いだろうか?

答えを言うと以下のようにすればよい。

tail -f log.txt > >(grep 'keyword') &
echo $!        # $!はtailのプロセスIDになっている

ここで見慣れない文法 >( コマンド ) というものがある。
これはコマンド置換と呼ばれるbashの文法で、コマンドを実行したときのIOをファイルのように扱うことができるものである。
(参考:https://techblog.raccoon.ne.jp/archives/53726690.html )
つまり、tail -f ...の結果をリダイレクトした先は本来ならファイルであるはずだが、そのファイルへの書き出しがgrep ...の標準入力に渡されるようになる。
一般にプロセス置換を使うと cmd1 | cmd2 とパイプで繋ぐものと等価なものがcmd1 > >(cmd2)として実現できる。

しかし、パイプと違うのがバックグラウンド実行した際に$!で得られるプロセスID。コマンド置換を使った場合、前半のtailのコマンドのプロセスIDが取得される。
これによってkill $!としても、tailが残ってしまうことなく終了するし、ついでにgrepプロセスも終了する。

参考: https://stackoverflow.com/questions/1652680/how-to-get-the-pid-of-a-process-that-is-piped-to-another-process-in-bash

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1