내가 이것을 가지고 있다고 가정 해 봅시다 :
node a.js | node b.js | node c.js
a.js가 죽어가고 있다면 b.js를 죽일 수 있나요? 그 반대는 어떻습니까? 이 파이프를 구축하면 다른 프로세스가 종료/종료될 때 한 프로세스가 반드시 종료/종료되지는 않는 것 같습니다. 한 사람이 죽으면 어떻게 다 죽일 수 있겠습니까?
답변1
존재하다:
cmd1 | cmd2
cmd2
완료 시 자동으로 종료되지는 않지만 cmd1
표준 입력에서는 파일 끝이 표시됩니다. 이는 일반적으로 파이프라인이 끝나는 방식입니다.
존재하다:
echo foo | sed s/o/e/g
sed
echo
현재 표준 입력에서 더 이상 읽을 내용이 없다는 것을 발견했기 때문에 종료 후 종료됩니다 .
종료 시 cmd1
종료를 시도할 수 cmd2
있지만 파이프에 기록된 모든 항목을 cmd2
아직 읽지 않은 경우에는 어떻게 됩니까?cmd1
cmd2
먼저 죽으면 자동 cmd1
으로 죽지 않지만 다음에 (현재 손상된) 파이프에 쓰려고 하면 (SIGPIPE를 사용하여) 죽게 됩니다.
파이프라인은 다음과 같습니다.
yes | head
종료( 처음 10줄을 읽고 인쇄한 후 종료한 후 yes
파이프에 처음 쓸 때 종료됩니다 ).head
이제 파이프의 다른 쪽 끝에 있는 프로세스를 정말로 종료하려는 경우 파이프의 다른 쪽 끝에 어떤 프로세스가 파일 설명자를 가지고 있는지 알아낼 수 있는 이식 가능한 방법이 없습니다.
/proc/*/fd
Linux에서는 파이프 끝의 fd에 있는 파이프와 동일한 inode를 가진 파일을 찾을 수 있으며, 심볼릭 링크 자체에 대한 권한은 파이프의 어느 쪽 끝인지 나타냅니다.
$ (ls -lLi /proc/self/fd/3; ls -l /proc/self/fd/3) 3>&1 >&2 | (ls -Lil /proc/self/fd/0; ls -l /proc/self/fd/0)
224052 prw------- 1 chazelas chazelas 0 Sep 20 23:26 /proc/self/fd/3|
224052 prw------- 1 chazelas chazelas 0 Sep 20 23:26 /proc/self/fd/0|
l-wx------ 1 chazelas chazelas 64 Sep 20 23:26 /proc/self/fd/3 -> pipe:[224052]
lr-x------ 1 chazelas chazelas 64 Sep 20 23:26 /proc/self/fd/0 -> pipe:[224052]
동일한 파이프 inode의 경우 쓰기 측의 fd에 w
권한이 있고 읽기 측의 fd에 r
권한이 있습니다.
예를 들어, zsh
다음 명령을 사용하여 파이프의 읽기 끝에 fd가 있고 파이프의 다른 쪽 끝이 fd 3에 있는 프로세스의 pid를 가져올 수 있습니다.
pids=(/proc/<->/fd/*(Nf{u+r}e{'[[ $REPLY -ef /dev/fd/3 ]]'}-p:h:h:t))
pids=(${(u)pids}) # unique
예:
$ (pids=(/proc/<->/fd/*(Nf{u+r}e{'[[ $REPLY -ef /dev/fd/3 ]]'}-p:h:h:t))
pids=(${(u)pids}); ps -fp $pids) 3>&1 >&2 | tr a b
UID PID PPID C STIME TTY TIME CMD
chazelas 24157 11759 0 23:41 pts/1 00:00:00 tr a b
따라서 다음을 수행할 수 있습니다(여전히 Linux에서 를 사용하여 zsh
).
run_and_kill_the_other_end() {
setopt localoptions localtraps
trap : TERM
"$@"
local ret=$?
local -aU pids
if [ -p /dev/stdout ]; then
pids=(/proc/<2->/fd/<0-9>(Nf{u+r}e{'[[ $REPLY -ef /dev/stdout ]]'}-p:h:h:t))
exec >&- # give the right end a chance to see eof and act upon it
fi
[ -p /dev/stdin ] &&
pids+=(/proc/<2->/fd/<0-9>(Nf{u+w}e{'[[ $REPLY -ef /dev/stdin ]]'}-p:h:h:t))
(($#pids)) && kill $pids 2> /dev/null
return $ret
}
그런 다음:
run_and_kill_the_other_end node a.js | run_and_kill_the_other_end node b.js
그러나 이는 원하는 작업이 아닐 수도 있습니다. 예를 들어:
$ run_and_kill_the_other_end seq 100 |
run_and_kill_the_other_end sort |
run_and_kill_the_other_end wc -l
0
sort
정렬된 출력을 작성하기 전에 종료되었습니다. wc -l
탈출을 시도하십시오.
유예 기간으로 지연을 삽입할 수 있지만 지연 기간은 얼마나 되어야 합니까? 예를 들어 sleep 0.1
뒤에 추가 하면 다음 exec >&-
과 같이 표시됩니다.
$ run_and_kill_the_other_end seq 100 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
100
$ run_and_kill_the_other_end seq 10000 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
10000
$ run_and_kill_the_other_end seq 100000 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
0
이는 파이프라인 종료가 무조건 지연된다는 의미이기도 하다. 시간 제한이 있는 's'를 사용하여 zsh
이를 개선 할 수 있습니다.zselect