백그라운드로 파이프 된 명령 시퀀스에서 모든 명령의 PID 가져 오기


11

에서 bash에 다음을 실행하면

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

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

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



1
@ G-Man 케어 설명? 필자는 표면적 인 유사성 만 보았으며 Ramesh의 답변에서 설명했듯이 명령 세트를 수정하는 것은별로 유용하지 않습니다.
muru

피상적 인 유사성? cat /var/run/out | nc -l 8080아니라 표면적으로 유사cmd1 | cmd2? 베어 본 파이프 라인을 입력 한 다음 PID 복구 하려는 제약 조건 은 (1) 해당 질문에 명시되지 않았으며 (2) 좋은 일반적인 솔루션을 허용하지 않을 것입니다.
G-Man, 'Reinstate

@ G-Man 반대로, 당신은 간단한 언급되지 않은 제약을 부과하고 있습니다. cmd1 | cmd2두 PID를 쉽게 얻을 수있는 매우 특별한 경우입니다. n에 대해 뭐라고 했어? 그렇다면 왜 n = 2라고 가정합니까? cmdi가 무엇인지에 대해 이야기 했습니까? 왜 내가 cmdi를 수정할 수 있다고 가정합니까? 나는 일반적인 해결책을 요구하고 있으며 당신은 제한을 부과하고 있습니다.
muru

답변:


6

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

foo | bar | baz &
baz_pid=$!

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

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


목록에서 임의 명령의 PID를 요청하기 위해 질문을 편집해도 괜찮습니까? 아니면 새로운 질문을 시작해야합니까?
muru

아마도 그 답변에 대한 답변을 더 오래 기다려야 할 것입니다. 나는 stackexchange 사이트 구성에 대해 강한 감정을 가지고 있지 않으므로 별도의 질문, 질문 편집 등 무엇이든지 귀찮게하지 않을 것입니다.

괜찮습니다. 즉각적인 문제가 해결되었습니다. 이제 호기심이 생깁니다. 그런 다음 편집하겠습니다. 질문이 급격히 변하고 이전 답변이 제자리를 벗어난 것처럼 보이기 때문에 헤즈 업에 불과합니다.
muru

@muru-이것을 참조하는 새로운 Q로 만드는 것이 좋을 것입니다.
slm

@slm은 정식으로 언급했다. 앞으로 그렇게 할 것입니다.
muru

4

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

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

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


흥미롭지 만 명령 세트를 수정해야합니다. 명령이 실행 된 후에는 많이 사용하지 않습니다.
muru

@muru-무엇? 일단 실행이 끝나면 PID는 어떤 용도로 사용됩니까? 파이프 라인의 PID를 원하십니까? jobs -p. 로 신호를 보냅니다 SIGPIPE. 당신이 원하는 cmdi-이.
mikeserv

1
@mikeserv 우리가 말하는 것처럼 배경에 있으면 안됩니다. 어떤 명령으로 명령 줄을 수정해야합니까?
muru

1
@muru는 마법이 될 것입니다. 디버거가 필요합니다.
mikeserv

나는 이것이 백그라운드 프로세스를 시작하고, 어떤 상태에 도달하기를 기다렸다가 죽이는 데 유용한 패턴이라는 것을 알았습니다. 경우 아무도 관심 : gist.github.com/MatrixManAtYrService/...
MatrixManAtYrService

2

이식성이 높지 않은 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


0

이 코드에서는 제로 기반 배열을 사용합니다. 당신이 실행하는 것을 조심하십시오 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.