Perché questo `grep -v` non funziona come previsto?


12

Ho uno strano problema relativo alle grep -vquery. Mi permetta di spiegare:

Per visualizzare le connessioni che utilizzo 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)

La corrente ttydel mio terminale èpts/0

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

Tento di escludere la mia connessione utilizzando grep -v $(tty | cut -f3-4 -d'/'). L'output previsto di questo comando dovrebbe essere who, senza la mia connessione. Tuttavia, l'output è più imprevisto:

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

Allego le $(...)virgolette e sembra che risolva il problema "Nessun file o directory". Tuttavia, la mia connessione è ancora stampata anche se il mio tty ( pts/0) avrebbe dovuto essere escluso:

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

A partire da questo momento, non ho assolutamente idea del perché la grepquery non funzioni correttamente.


4
Che ne dici di usare set -xprima ... Quindi esegui il tuo comando e vedi cosa stai effettivamente cercando di grep...
don_crissti

@don_crissti ah, capisco; mi sta dicendo che in realtà grepnon sono un "tty". Come mi consiglieresti di aggirare questo?
forse

Risposte:


18

Zachary ha spiegato l'origine del problema.

Mentre puoi aggirarlo con

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

Sarebbe sbagliato come ad esempio se quel tty è pts/1, si finirebbe per escludere tutte le righe che contengono pts/10. Alcune grepimplementazioni hanno -wun'opzione per fare una ricerca per parola

who | grep -vw pts/1

non corrisponderebbe pts/10perché l'interno pts/1non è seguito da un carattere non verbale.

Oppure puoi usare awkper filtrare il valore esatto del secondo campo come:

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

Se vuoi farlo in un solo comando:

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

Lo stdin originale viene duplicato sul descrittore di file 3 e ripristinato per il ttycomando.


3
+1 per capire come farlo in un solo comando e sottolineare quell'errore.
Zachary Brady,

Un altro liner:tty | cut -f3-4 -d'/' | xargs -I % sh -c "who | grep -v %"
axxis

20

Dalla pagina di informazioni tty.

'tty' stampa il nome del file del terminale collegato al suo input standard. Stampa `non un tty 'se l'ingresso standard non è un terminale.

Il problema è che nel tuo esempio lo stdin di tty è una pipe, non il tuo terminale.

Puoi vedere da questo esempio.

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

Per ovviare a questo, potresti fare qualcosa del genere.

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

C'è un modo più veloce / più efficiente, tuttavia richiede due comandi.

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

@Christopher sei l'unico ad aver effettuato l'accesso al tuo computer?
Zachary Brady,

@Christopher, weird. Quindi who | grep -v "$(ps ax | grep "^$$" | awk '{ print $2 }')"produce l'output previsto sulla mia scatola e t=$(tty) who|grep -v "${t:5}"non produce nulla.
Zachary Brady,

Quale shell / versione stai usando? GNU bash, version 4.1.2
Zachary Brady,

2
ps ax | grep "^ *$$"potrebbe corrispondere in modo errato, ad esempio se la shell è 123 e 1234 esiste; ps ax -otty= $$è più robusto e solo un processo. Ma preferisco il tuo ${t:5}o Stephane ${t#/dev/}(o substr(t,6))
dave_thompson_085

1
Si prega di non aggiungere dichiarazioni di non responsabilità. Mentre l'intento è lodevole, non aiutano davvero la risposta. Se qualcuno evidenzia un difetto nella tua risposta, modifica la tua risposta per incorporare la correzione.
terdon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.