と呼ばれる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
そのため、パイプのiノードを持っているよりも:)パイプの他のすべてのプロセスを検索できます/proc/
。次に、あなたにパイプしているコマンドがあります:
% lsof | grep 124149866
cat 29889 xyz 1w FIFO 0,6 124149866 pipe
sh 29890 xyz 0r FIFO 0,6 124149866 pipe
この例では、cat
パイプでワードに渡されsh
ます。で/proc/29889
あなたが呼ばれるファイルを見つけることができcmdline
ますを伝え、正確に何と呼ばれていました。
% cat /proc/29889/cmdline
cat/dev/zero%
コマンドラインのフィールドはNULで区切られているため、少し見苦しく見えます:)
lsof
最新のLinuxディストリビューションで最新の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