web-dev-qa-db-ja.com

コマンドのバックグラウンドでパイプされたシーケンス内の任意のコマンドのPIDを取得します

bashで、私が実行すると:

cmd1 | cmd2 | ... | cmdi | ... | cmdn &

cmd{1..n}が明確でない場合、cmdiのPIDを取得するにはどうすればよいですか?または、cmdiプロセスにシグナルを送るにはどうすればよいですか? (たとえば、それをSIGUSR1?に送信します)pkill/pgreppidofなどは、cmdiおそらく同じパイプラインの一部として実行されています。 jobs -pは、cmd1のPIDを提供します。

i{1..n}の任意の文字にすることができます。

11
muru

質問の元のバージョンでは、最後のコマンドのPIDのみが必要な場合、特殊変数$!が最適です。

foo | bar | baz &
baz_pid=$!

他のプロセスのPIDへの同様の簡単なアクセスはありません。

$pipestatus(zsh)と$PIPESTATUS(bash)が追加されるまでに長い時間がかかり、最終的に$?に加えて、パイプラインのすべての終了ステータスにアクセスできるようになりました元のボーンシェル以来存在していた最後の1つです。多分類似の何かが$!で最終的に発生します。

6
user41515

私はあなたが提案されたように何かをすることができると思います ここ

(ls -l | echo "Hello" | df -h & echo $! >&3 ) 3>pid

ここで上記の例では、3番目のパイプ処理されたプロセスのpidを取得し、それをファイルpidまで書き留めました。パイプ処理されたプロセスについては、それを書き留めることができます。

4
Ramesh

移植性が高くないLinux固有のソリューションは、プロセスを接続するパイプを使用してプロセスを追跡することです。最初の(jobs -p) そして最後 ($!)パイプライン内のコマンド。どちらのPIDを使用しても、このスクリプトは次のようなことができます。

#! /bin/bash

PROC=$1
echo $PROC

if [[ $(readlink /proc/$PROC/fd/1) =~ ^pipe: ]]
then
    # Assuming first process in chain...
    NEXT_FD=1
Elif [[ $(readlink /proc/$PROC/fd/0) =~ ^pipe: ]]
then
    # Last process in chain...
    NEXT_FD=0
else
    # Doesn't look like a pipe.
    exit
fi

NEXT_PROC_PIPE=$(readlink /proc/$PROC/fd/$NEXT_FD)

while [[ $NEXT_PROC_PIPE =~ ^pipe: ]] 
do
    PROC=$(find /proc/*/fd -type l -printf "%p/%l\n" 2>/dev/null | awk -F'/' '($6 == "'"$NEXT_PROC_PIPE"'") && ($3 != "'$PROC'" ) {print $3}')
    NEXT_PROC_PIPE=$(readlink /proc/$PROC/fd/$NEXT_FD)
    echo $PROC
done
2
muru

このコードでは、ここではゼロベースの配列を使用しています。 evalが実行する内容に注意してください。

#!/bin/bash

cmd=('sleep 10' 'sleep 2' 'sleep 5')
first=1
for c in "${cmd[@]}"; do
  ((first)) && { pipe=$c; first=0; } || pipe+='|'$c
done
shopt -u lastpipe
eval $pipe &

printf 'Pipe:\n%s\n\n' "$pipe"

shellpid=$BASHPID
parent=$(ps -o pid= --ppid $shellpid | head -n -1)
declare -a pids=()
mapfile -t pids < <(printf '%s\n' $(ps -o pid= --ppid $parent))
printf '%s\n' 'Listing the arrays:'
printf '%2s %6s %s\n' i PID command
for i in "${!cmd[@]}"; do
    printf '%2d %6d %s\n' "$i" "${pids[i]}" "${cmd[i]}"
done

printf '\n%s\n' 'ps listing:'
ps xao pid,ppid,command | head -n 1
ps xao pid,ppid,command | tail | head -n -3
0
jarno