백그라운드로 파이프 된 명령 시퀀스에서 모든 명령의 PID 가져 오기 | cmdn & 어디에서 cmd{1..n}구별되지 않을

에서 bash에 다음을 실행하면

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

어디에서 cmd{1..n}구별되지 않을 수 cmdi있습니까? PID는 어떻게 얻 습니까? 또는 cmdi프로세스에 신호를 보내려면 어떻게 해야합니까? (예를 들어, 보내 SIGUSR1?)
pkill/ pgrep, pidof등 좋은 답변처럼 보이지 않는, 다른 인스턴스 때문에 cmdi어쩌면, 실행되는 동일한 파이프 라인의 한 부분으로 포함된다. jobs -p의 PID를 제공합니다 cmd1.

i에있을 수 있습니다 {1..n}.



답변

질문의 원래 버전의 경우 마지막 명령의 PID 만 원할 때 특수 변수 $!가 완벽합니다.

foo | bar | baz &
baz_pid=$!

다른 프로세스의 PID에 쉽게 접근 할 수는 없습니다.

$pipestatus(zsh) 및 $PIPESTATUS(bash)가 추가 되는 데 오랜 시간이 걸렸으며 , 최종적으로 $?Bourne 쉘 이후 마지막 에 있던 파이프 라인의 모든 종료 상태에 액세스 할 수있게 되었습니다. 어쩌면 비슷한 일이 일어날 수도 $!있습니다.


답변

나는 당신이 여기에 제안한대로 뭔가를 할 수 있다고 생각합니다 .

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

위의 예에서, 세 번째 파이프 프로세스의 pid를 검색하여 pid 파일에 기록했습니다. 파이프 프로세스에 대해 적어 둘 수 있습니다.


답변

이식성이 높지 않은 Linux 전용 솔루션은 프로세스를 연결하는 파이프를 사용하여 프로세스를 추적 할 수 있습니다. 파이프 라인에서 첫 번째 ( jobs -p) 및 마지막 ( $!) 명령 의 PID를 얻을 수 있습니다 . 이 스크립트는 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

답변

이 코드에서는 제로 기반 배열을 사용합니다. 당신이 실행하는 것을 조심하십시오 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