どのようにして、実際のコマンドを決定していますか?


9

と呼ばれるbashスクリプトがあるとしlog.shます。このスクリプトでは、パイプから入力を読み取りたいのですが、パイプで入力を入力するために使用するコマンドも知りたいです。例:

tail -f /var/log/httpd/error | log.sh

シェルスクリプトで、コマンドについて知りたいtail -f /var/log/httpd/error


なぜこれが必要なのか、私は非常に興味があります。
Ignacio Vazquez-Abrams

私の推測では、pidをキャプチャして処理するGUIプログラムを作成していますか?
palbakulich、2011

結果をどこに置くか区別できるように知りたいのですが。コマンドとファイル名に応じて、さまざまなアクションを実行したいと思います。
セントジョンソンジョン

4
それは、私にとって最小の驚きの原則に対する重大な違反のように思えます。スクリプトがさまざまな状況でさまざまなことを行う必要がある場合、それは、その入力元からではなく、コマンドラインオプションによって制御する必要があります。
Dave Sherohman、2011

@デイブ、同意する。この例のために、着信コマンドが何であるかを「知りたい」としましょう。
セントジョンソンジョンソン

回答:


7

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

この巨大な投稿の代わりに、私はlsofベースのスクリプトで2番目の答えを出したでしょう。そのための素晴らしい仕事。
akira

@akiraありがとう。クリーンでポータブルなものにするために数回の試みが必要でした。途中でprocfsとlsofについていくつかのことを学びました。アイデアをありがとう。
ミケル

他の人が直接使える答えが出るので受け入れました。@あきら、あなたはほとんどの仕事をしてくれました、すみません、あなたの仕事も受け入れられませんでした。
セントジョンソンジョン

10

パイプは、プロセスの開いているファイル記述子のリストのエントリとして表示されます。

 % 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で区切られているため、少し見苦しく見えます:)


どの回答を受け入れるかわかりません。@Akira、あなたはそれをどのように決定するかに関して実際の内訳を与え、@ Mikelは私にスクリプトを与えました。物事を素晴らしい+困難にする方法。
セントジョンジョンソン

1

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を生成します。

ご了承ください:

  1. ソース側に複数のPIDが見つかる{ echo Hi; sleep 5 ; } | whatpipe.sh可能性がbashありsleep 5ます。たとえば、(入力サブシェル)とが生成される可能性があります。
  2. +Elsofコンパイルされた場合にのみ使用できます-DHASUXSOCKEPT。これは、最新のLinuxディストリビューションのほとんどに当てはまるはずですが、とにかく次の方法でインストールを確認してください。lsof -v 2>&1 | grep HASUXSOCKEPT
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.