この「grep -v」が期待どおりに機能しないのはなぜですか?

この「grep -v」が期待どおりに機能しないのはなぜですか?

queryに関連する奇妙な問題がありますgrep -v。説明をお願いします:

私が使用している接続を表示するにはwho

$ who
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

tty私の端末は現在pts/0

$ tty
/dev/pts/0
$ tty | cut -f3-4 -d'/'
pts/0

私の接続を除外してみましたgrep -v $(tty | cut -f3-4 -d'/')。接続なしでこのコマンドの期待される出力はですwho。しかし、出力は最も予想外のものです。

$ who | grep -v $(tty | cut -f3-4 -d'/')
grep: a: No such file or directory
grep: tty: No such file or directory

私はそれを$(...)引用符で囲み、「対応するファイルやディレクトリがありません」という問題を解決しているようです。しかし、私のtty(pts/0)を除外する必要がありますが、私の接続はまだ印刷されています。

$ who | grep -v "$(tty | cut -f3-4 -d'/')"
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

grepこれまでクエリが失敗した理由はまったくわかりません。

答え1

tty情報ページから。

'tty' は標準入力に接続された端末のファイル名を出力します。標準入力が端末でない場合は、「ttyではない」を印刷します。

問題は、あなたの場合、ttyの標準入力が端末ではなくパイプであることです。

これはこの例で見ることができます。

$ tty
/dev/pts/29
$ echo | tty 
not a tty

この問題を解決するには、次のようにします。

who | grep -wv "$(ps ax | awk "\$1 == $$ {print \$2}" )"

より高速で効率的な方法がありますが、2つのコマンドが必要です。

t=$(tty)
who|grep -wv "${t:5}"

答え2

Zacharyは問題の根本原因を説明しました。

解決できますが、

tty=$(tty)
tty_without_dev=${tty#/dev/}
who | grep -v "$tty_without_dev"

これは間違っています。たとえば、ttyをpts/1含むすべての行を除外する場合ですpts/10。一部の実装では、単語検索を実行するオプションがgrepあります。-w

who | grep -vw pts/1

後ろに単語以外の文字がないpts/10ため、一致しません。pts/1

または、awk次の例を使用して、2番目のフィールドの正確な値をフィルタリングできます。

who | awk -v "tty=$tty_without_dev" '$2 != tty'

1 つのコマンドで実行するには、次のようにします。

{ who | awk -v "tty=$(tty<&3)" '$2 != substr(tty,6)'; } 3<&0

元の標準入力はファイル記述子3にコピーされ、ttyコマンドに対して復元されます。

関連情報