web-dev-qa-db-ja.com

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

_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クエリが正常に機能しない理由はまったくわかりません。

12

Zacharyが問題の原因を説明しています。

あなたはそれを回避することができますが

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

たとえば、そのttyがpts/1である場合、pts/10を含むすべての行を除外することになるため、これは誤りです。一部のgrep実装には、Word検索を実行するための-wオプションがあります

who | grep -vw pts/1

中のpts/10の後にWord以外の文字が続いていないため、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

元のstdinはファイル記述子3に複製され、ttyコマンド用に復元されます。

18

Tty情報ページから。

'tty'は、標準入力に接続されている端末のファイル名を出力します。標準入力が端末でない場合、「ttyではありません」と出力します。

問題は、あなたの例ではttyのstdinが端末ではなくパイプであることです。

この例からわかるでしょう。

$ 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}"
20
Zachary Brady