Pourquoi ce `grep -v` ne fonctionne pas comme prévu?


12

J'ai un problème étrange lié aux grep -vrequêtes. Permettez-moi d'expliquer:

Pour afficher les connexions que j'utilise 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)

Le courant ttyde mon terminal estpts/0

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

J'essaie d'exclure ma propre connexion en utilisant grep -v $(tty | cut -f3-4 -d'/'). La sortie attendue de cette commande devrait être who, sans ma connexion. Cependant, la sortie est la plus inattendue:

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

Je joins les $(...)guillemets et cela semble résoudre le problème "Aucun fichier ou répertoire". Cependant, ma connexion est toujours imprimée même si mon tty ( pts/0) aurait dû être exclu:

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

À partir de ce point, je n'ai absolument aucune idée pourquoi la greprequête fonctionne mal.


4
Que diriez-vous d'utiliser d' set -xabord ... Ensuite, exécutez votre commande et voyez ce que vous essayez réellement de faire grep...
don_crissti

@don_crissti ah, je vois; ça me dit que je suis en fait grep"pas un tty". Comment suggéreriez-vous que je contourne cela?
peut

Réponses:


18

Zachary a expliqué la source du problème.

Bien que vous puissiez contourner ce problème avec

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

Ce serait faux car, par exemple, si ce tty est pts/1, vous finirez par exclure toutes les lignes contenant pts/10. Certaines grepimplémentations ont une -woption pour faire une recherche de mots

who | grep -vw pts/1

ne correspondrait pas pts/10parce que le caractère pts/1in there n'est pas suivi d'un caractère autre qu'un mot.

Ou vous pouvez utiliser awkpour filtrer la valeur exacte du deuxième champ comme:

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

Si vous voulez le faire en une seule commande:

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

Le stdin d'origine étant dupliqué sur le descripteur de fichier 3 et restauré pour la ttycommande.


3
+1 pour avoir compris comment le faire en une seule commande et signalé cette erreur.
Zachary Brady

tty | cut -f3-4 -d'/' | xargs -I % sh -c "who | grep -v %"
Encore

20

Depuis la page d'informations tty.

'tty' imprime le nom de fichier du terminal connecté à son entrée standard. Il imprime «pas un tty» si l'entrée standard n'est pas un terminal.

Le problème est que dans votre exemple, le stdin de tty est un tube, pas votre terminal.

Vous pouvez voir sur cet exemple.

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

Pour contourner cela, vous pourriez faire quelque chose comme ça.

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

Il existe un moyen plus rapide / plus efficace, mais il nécessite deux commandes.

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

@Christopher êtes-vous le seul à être connecté à votre ordinateur?
Zachary Brady

@Christopher, bizarre. Donc, le who | grep -v "$(ps ax | grep "^$$" | awk '{ print $2 }')"produit la sortie attendue sur ma boîte et t=$(tty) who|grep -v "${t:5}"ne produit rien.
Zachary Brady du

Quel shell / version utilisez-vous? GNU bash, version 4.1.2
Zachary Brady

2
ps ax | grep "^ *$$"pourrait fausser la correspondance, par exemple votre shell est 123 et 1234 existe; ps ax -otty= $$est plus robuste et un seul processus. Mais je préfère le vôtre ${t:5}ou celui de Stéphane ${t#/dev/}(ou substr(t,6))
dave_thompson_085

1
Veuillez ne pas ajouter d'exonération de responsabilité. Bien que l'intention soit louable, ils n'aident pas vraiment la réponse. Si quelqu'un signale une faille dans votre réponse, modifiez simplement votre réponse pour incorporer la correction.
terdon
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.