라는 bash 스크립트가 있다고 가정 해 봅시다 log.sh
. 이 스크립트에서는 파이프에서 입력을 읽고 싶지만 입력을 파이프로 보내는 데 사용되는 명령을 알고 싶습니다. 예:
tail -f /var/log/httpd/error | log.sh
쉘 스크립트에서 나는 명령을 알고 싶다 tail -f /var/log/httpd/error
.
라는 bash 스크립트가 있다고 가정 해 봅시다 log.sh
. 이 스크립트에서는 파이프에서 입력을 읽고 싶지만 입력을 파이프로 보내는 데 사용되는 명령을 알고 싶습니다. 예:
tail -f /var/log/httpd/error | log.sh
쉘 스크립트에서 나는 명령을 알고 싶다 tail -f /var/log/httpd/error
.
답변:
Akira는을 (를) 사용하도록 제안했습니다 lsof
.
스크립트를 작성하는 방법은 다음과 같습니다.
whatpipe2.sh
#!/bin/bash
pid=$$
pgid=$(ps -o pgid= -p $pid)
lsofout=$(lsof -g $pgid)
pipenode=$(echo "$lsofout" | awk '$5 == "0r" { print $9 }')
otherpids=$(echo "$lsofout" | awk '$5 == "1w" { print $2 }')
for pid in $otherpids; do
if cmd=$(ps -o cmd= -p $pid 2>/dev/null); then
echo "$cmd"
break
fi
done
그것을 실행 :
$ tail -f /var/log/messages | ./whatpipe2.sh
tail -f /var/log/messages
^C
다른 방법은 프로세스 그룹을 사용하는 것입니다.
whatpipe1.sh
#!/bin/bash
pid=$$
# ps output is nasty, can (and usually does) start with spaces
# to handle this, I don't quote the "if test $_pgrp = $pgrp" line below
pgrp=$(ps -o pgrp= -p $pid)
psout=$(ps -o pgrp= -o pid= -o cmd=)
echo "$psout" | while read _pgrp _pid _cmd; do
if test $_pgrp = $pgrp; then
if test $_pid != $pid; then
case $_cmd in
ps*)
# don't print the "ps" we ran to get this info
# XXX but this actually means we exclude any "ps" command :-(
;;
*)
echo "$_cmd"
;;
esac
fi
fi
done
그것을 실행 :
$ tail -f /var/log/messages | ./whatpipe1.sh
tail -f /var/log/messages
^C
파이프 왼쪽의 명령이 파이프 ps
를 볼 수 있을 정도로 오랫동안 실행될 경우에만 작동 합니다. 와 함께 사용한다고 말 tail -f
했으므로 이것이 문제인 것 같습니다.
$ sleep 0 | ./whatpipe1.sh
$ sleep 1 | ./whatpipe1.sh
sleep 1
파이프는 프로세스의 열린 파일 설명자 목록에 항목으로 나타납니다.
% ls -l /proc/PID/fd
lr-x------ 1 xyz xyz 64 Feb 11 08:05 0 -> pipe:[124149866]
lrwx------ 1 xyz xyz 64 Feb 11 08:05 1 -> /dev/pts/2
lrwx------ 1 xyz xyz 64 Feb 11 08:05 2 -> /dev/pts/2
lr-x------ 1 xyz xyz 64 Feb 11 08:05 10 -> /tmp/foo.sh
다음과 같은 것을 사용할 수도 있습니다.
% lsof -p PID
sh 29890 xyz cwd DIR 0,44 4096 77712070 /tmp
sh 29890 xyz rtd DIR 0,44 4096 74368803 /
sh 29890 xyz txt REG 0,44 83888 77597729 /bin/dash
sh 29890 xyz mem REG 0,44 1405508 79888619 /lib/tls/i686/cmov/libc-2.11.1.so
sh 29890 xyz mem REG 0,44 113964 79874782 /lib/ld-2.11.1.so
sh 29890 xyz 0r FIFO 0,6 124149866 pipe
sh 29890 xyz 1u CHR 136,2 4 /dev/pts/2
sh 29890 xyz 2u CHR 136,2 4 /dev/pts/2
sh 29890 xyz 10r REG 0,44 66 77712115 /tmp/foo.sh
따라서 파이프의 inode가있는 것보다 :) 이제 /proc/
해당 파이프 에 대한 다른 모든 프로세스를 검색 할 수 있습니다 . 그러면 당신에게 배관 명령이있을 것입니다 :
% lsof | grep 124149866
cat 29889 xyz 1w FIFO 0,6 124149866 pipe
sh 29890 xyz 0r FIFO 0,6 124149866 pipe
이 예에서는 cat
wards로 파이프되었습니다 sh
. 에 /proc/29889
당신이라는 파일을 찾을 수 있습니다 cmdline
정확히 불렀다 무엇을 알려줍니다 :
% cat /proc/29889/cmdline
cat/dev/zero%
명령 줄의 필드는 NUL로 구분되므로 약간 추한 것처럼 보입니다. :)
lsof
최신 Linux 배포판을 사용하는 컴팩트 솔루션은 다음과 같습니다 .
cmd=$(lsof -t -p $$ -a -d 0 +E | while read p; do
[ $p -ne $$ ] && echo "$(tr \\000 " " </proc/$p/cmdline)"
done)
+E
현재 쉘 프로세스 ( -p $$ -a -d 0
)에서 FD 0 의 엔드 포인트 파일 ( )을 나열한 다음 출력을 PID로만 제한 ( -t
)하여 파이프의 양쪽에 PID를 생성합니다.
참고 :
{ echo Hi; sleep 5 ; } | whatpipe.sh
가능성이 산출됩니다 bash
(입력 서브 쉘을)과 sleep 5
.+E
lsof
로 컴파일 된 경우에만 사용할 수 있습니다 -DHASUXSOCKEPT
. 대부분의 최신 Linux 배포판에는 적용되지만 어쨌든 설치를 확인하십시오.lsof -v 2>&1 | grep HASUXSOCKEPT