Warum funktioniert das `grep -v` nicht wie erwartet?

12

Ich habe ein seltsames Problem im Zusammenhang mit grep -vAbfragen. Lassen Sie mich erklären:

So zeigen Sie Verbindungen an, die ich verwende 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)

Der Strom ttymeines Terminals istpts/0

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

Ich versuche meine eigene Verbindung mit auszuschließen grep -v $(tty | cut -f3-4 -d'/'). Die erwartete Ausgabe dieses Befehls sollte whoohne meine Verbindung sein. Die Ausgabe ist jedoch höchst unerwartet:

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

Ich füge die $(...)in Anführungszeichen und das scheint das Problem "Keine solche Datei oder Verzeichnis" zu beheben. Meine Verbindung wird jedoch weiterhin gedruckt, obwohl mein tty ( pts/0) hätte ausgeschlossen werden sollen:

$ 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)

Zum jetzigen Zeitpunkt habe ich absolut keine Ahnung, warum die grepAbfrage fehlerhaft ist.

vielleicht doch
quelle
4
Wie wäre es set -xzuerst mit ... Dann führen Sie Ihren Befehl und sehen, was Sie tatsächlich versuchen grep...
don_crissti
@don_crissti ah, ich verstehe; Es sagt mir, dass ich eigentlich grep"kein bisschen" bin . Wie würden Sie vorschlagen, dass ich das umgehen soll?
Vielleicht
Verwenden Sie eine Variable: tldp.org/HOWTO/Bash-Prompt-HOWTO/x721.html
don_crissti

Antworten:

18

Zachary hat die Ursache des Problems erklärt.

Während Sie damit umgehen können

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

Das wäre falsch, zum Beispiel, wenn das tty ist pts/1, würden Sie am Ende alle Zeilen ausschließen, die enthalten pts/10. Einige grepImplementierungen haben die -wOption, eine Wortsuche durchzuführen

who | grep -vw pts/1

würde nicht mit on übereinstimmen, pts/10da dem pts/1in dort kein Nicht-Wort-Zeichen folgt.

Oder Sie können awkden genauen Wert des zweiten Feldes wie folgt filtern:

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

Wenn Sie es in einem Befehl tun möchten:

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

Das ursprüngliche stdin wird auf Dateideskriptor 3 dupliziert und für den ttyBefehl wiederhergestellt .

Stéphane Chazelas
quelle
3
+1, um herauszufinden, wie es mit einem Befehl gemacht wird, und um auf diesen Fehler hinzuweisen.
Zachary Brady
Ein weiterer tty | cut -f3-4 -d'/' | xargs -I % sh -c "who | grep -v %"
Einzeiler
20

Von der tty info Seite.

'tty' gibt den Dateinamen des Terminals aus, das mit seiner Standardeingabe verbunden ist. Es wird `not a tty 'ausgegeben, wenn die Standardeingabe kein Terminal ist.

Das Problem ist, dass in Ihrem Beispiel tty stdin eine Pipe ist, nicht Ihr Terminal.

Sie können aus diesem Beispiel sehen.

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

Um das zu umgehen, könnten Sie so etwas tun.

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

Es gibt eine schnellere / effizientere Methode, für die jedoch zwei Befehle erforderlich sind.

t=$(tty)
who|grep -wv "${t:5}"
Zachary Brady
quelle
@Christopher bist du der einzige, der an deinem Computer angemeldet ist?
Zachary Brady
@ Christopher, komisch. Also das who | grep -v "$(ps ax | grep "^$$" | awk '{ print $2 }')"produziert die erwartete Ausgabe auf meiner Box und t=$(tty) who|grep -v "${t:5}"produziert nichts.
Zachary Brady
Welche Shell / Version benutzt du? GNU bash, version 4.1.2
Zachary Brady
2
ps ax | grep "^ *$$"könnte falsch übereinstimmen, z. B. ist Ihre Shell 123 und 1234 existiert; ps ax -otty= $$ist robuster und nur ein Prozess. Aber ich bevorzuge deine ${t:5}oder Stephanes ${t#/dev/}(oder substr(t,6))
dave_thompson_085
1
Bitte fügen Sie keine Haftungsausschlüsse hinzu. Obwohl die Absicht lobenswert ist, helfen sie der Antwort nicht wirklich. Wenn jemand auf einen Fehler in Ihrer Antwort hinweist, bearbeiten Sie einfach Ihre Antwort, um die Korrektur zu übernehmen.
terdon