GNU/Linux >> Tutoriels Linux >  >> Ubuntu

Comment une commande (c'est-à-dire Grep) sait-elle quand elle est exécutée dans le cadre de l'expansion Glob ?

Selon ma compréhension, un caractère générique glob est interprété par le shell, qui exécute ensuite la commande donnée pour chaque nom de fichier correspondant. Supposons que j'ai des fichiers :abc1, abc2, and abc3 dans mon répertoire actuel. Ensuite, par exemple, echo abc* fera écho une fois pour chaque nom de fichier commençant par "abc".

Cependant, si je lance grep 'foo' abc* , j'imagine que cela devrait fonctionner :

grep 'foo' abc1
grep 'foo' abc2
grep 'foo' abc3

Ce qui signifie que je devrais obtenir le résultat suivant (en supposant que tous les fichiers contiennent une ligne indiquant "foo") :

foo
foo
foo

Cependant, à la place, j'obtiens :

abc1:foo
abc2:foo
abc3:foo

Je pense donc qu'il y a 2 explications possibles à cela. Tout d'abord, grep peut en quelque sorte détecter qu'il a été utilisé avec une expression glob et répond en affichant les noms de fichiers avant les correspondances. Deuxièmement, puisque vous pouvez transmettre plusieurs fichiers à grep, le shell n'exécute en réalité qu'une seule commande :

grep 'foo' abc1 abc2 abc3

Cependant, cela ne fonctionne que parce que grep accepte plusieurs fichiers à la fin. Il est possible qu'une autre commande n'autorise qu'un seul fichier à transmettre. Donc, si vous vouliez exécuter la commande pour plusieurs fichiers correspondant au glob, cela ne fonctionnerait pas si le globbing fonctionnait via la deuxième méthode décrite ci-dessus.

Quoi qu'il en soit, quelqu'un peut-il nous éclairer là-dessus ?

Merci !

Réponse acceptée :

C'est le truc :la commande ne sait pas, c'est le shell qui fait le travail

Considérons par exemple grep 'abc' *.txt . Si nous exécutons la trace des appels système, vous verrez quelque chose comme ceci :

bash-4.3$ strace -e trace=execve grep "abc" *.txt > /dev/null
execve("/bin/grep", ["grep", "abc", "ADDA_converters.txt", "after.txt", "altera_license.txt", "altera.txt", "ANALOG_DIGITAL_NOTES.txt", "androiddev.txt", "answer2.txt", "answer.txt", "ANSWER.txt", "ascii.txt", "askubuntu-profile.txt", "AskUbuntu_Translators.txt", "a.txt", "bash_result.txt", ...], [/* 80 vars */]) = 0
+++ exited with 0 +++

Le shell a développé *.txt dans tous les noms de fichiers du répertoire courant qui se terminent par .txt extension. Donc, efficacement, votre shell traduit le grep 'abc' *.txt commande dans grep 'abc' file1.txt file2.txt file3.txt . . . . Ainsi, votre deuxième hypothèse est correcte.

La première hypothèse n'est pas correcte - les programmes n'ont aucun moyen de détecter glob. Il est possible de passer * comme argument de chaîne à la commande, mais c'est le travail de la commande de décider quoi en faire ensuite. L'expansion du nom de fichier, cependant, est la propriété de votre shell respectif, comme je l'ai déjà mentionné.

Cependant, cela ne fonctionne que parce que grep accepte plusieurs fichiers à la fin. Il est possible qu'une autre commande n'autorise qu'un seul fichier à transmettre.

Exactement exact ! Les programmes ne limitent pas le nombre d'arguments de ligne de commande acceptables (par exemple, en C, c'est un tableau de chaînes const char *args[] et en python sys.argv[] ), mais ils peuvent détecter la longueur de ce tableau ou si quelque chose d'inattendu est dans la mauvaise position du tableau. grep ne le fait pas et accepte plusieurs fichiers, ce qui est voulu par sa conception.

Connexe :Après la mise à niveau vers Ubuntu 13.10, Firefox fait parfois planter l'ordinateur ?

En passant, des citations incorrectes couplées à un globbing avec grep peuvent parfois être un problème. Considérez ceci :

bash-4.3$ echo "one two" | strace -e trace=execve grep *est*
execve("/bin/grep", ["grep", "self_test.sh", "test.wxg"], [/* 80 vars */]) = 0
+++ exited with 1 +++

Un utilisateur non préparé s'attendrait à ce que grep corresponde à n'importe quelle ligne avec est lettres qu'il contient provenant du tuyau, mais à la place, l'expansion du nom de fichier du shell a tout tordu. J'ai souvent vu cela arriver avec des gens qui font ps aux | grep shell_script_name.sh , et ils s'attendent à trouver leur processus en cours d'exécution, mais parce qu'ils ont exécuté la commande à partir du même répertoire où le script était , l'expansion du nom de fichier du shell a fait grep commande pour avoir un aspect complètement différent dans les coulisses de ce à quoi l'utilisateur s'attendait.

La bonne façon serait d'utiliser des guillemets simples :

bash-4.3$ echo "one two" | strace -e trace=execve grep '*est*'
execve("/bin/grep", ["grep", "*est*"], [/* 80 vars */]) = 0
+++ exited with 1 +++

Ubuntu
  1. Comment utiliser la commande Linux grep

  2. Comment exécuter une commande stockée dans une variable ?

  3. Comment fonctionne la commande Tee ? ?

  4. Comment masquer la sortie du terminal lors de l'exécution d'une commande ?

  5. Comment exécuter une application pendant une durée définie dans Shell ?

COMMENT UTILISER TAIL COMMAND

Comment utiliser la commande head

Comment utiliser grep sous Linux

Comment gérer les snaps sous Linux – Partie 2

Que fait la commande Startx ?

Qu'est-ce que la commande Grep sous Linux ? Pourquoi est-il utilisé et comment fonctionne-t-il ?