GNU/Linux >> Linux Esercitazione >  >> Ubuntu

Come fa un comando (es. Grep) a sapere quando viene eseguito come parte dell'espansione glob?

Secondo la mia comprensione, un carattere jolly glob viene interpretato dalla shell, che quindi esegue il comando fornito per ogni nome file corrispondente. Supponiamo di avere file:abc1, abc2, and abc3 nella mia directory attuale. Quindi, ad esempio, echo abc* farà eco una volta per ogni nome di file che inizia con 'abc'.

Tuttavia, se eseguo grep 'foo' abc* , immagino che dovrebbe essere eseguito:

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

Ciò significa che dovrei ottenere il seguente output (supponendo che tutti i file contengano una riga che dice "foo"):

foo
foo
foo

Tuttavia, invece ottengo:

abc1:foo
abc2:foo
abc3:foo

Quindi immagino che ci siano 2 possibili spiegazioni per questo. Primo, in qualche modo grep può rilevare che è stato usato con espressioni glob e risponde emettendo i nomi dei file prima delle corrispondenze. In secondo luogo, poiché puoi passare più file a grep, la shell esegue effettivamente solo 1 comando:

grep 'foo' abc1 abc2 abc3

Tuttavia, questo funziona solo perché grep accetta più file alla fine. È possibile che un altro comando consenta solo il passaggio di 1 file. Quindi, se si desidera eseguire il comando per più file corrispondenti al glob, non funzionerebbe se il globbing funzionasse tramite il secondo metodo descritto sopra.

Ad ogni modo, qualcuno può fare luce su questo?

Grazie!

Risposta accettata:

Questo è il trucco:il comando non lo sa, è la shell che fa il lavoro

Si consideri ad esempio grep 'abc' *.txt . Se eseguiamo la traccia delle chiamate di sistema, vedrai qualcosa del genere:

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 +++

La shell ha espanso *.txt in tutti i nomi di file nella directory corrente che terminano con .txt estensione. In modo così efficace, la tua shell traduce il grep 'abc' *.txt comando in grep 'abc' file1.txt file2.txt file3.txt . . . . Quindi, la tua seconda ipotesi è corretta.

La prima ipotesi non è corretta:i programmi non hanno modo di rilevare il globo. È possibile passare * come argomento stringa da comandare, ma è compito del comando decidere cosa farne allora. L'espansione del nome del file, tuttavia, è di proprietà della rispettiva shell, come ho già detto.

Tuttavia, questo funziona solo perché grep accetta più file alla fine. È possibile che un altro comando consenta solo il passaggio di 1 file.

Completamente giusto ! I programmi non limitano il numero di argomenti accettabili della riga di comando (ad esempio, in C è un array di stringhe const char *args[] e in Python sys.argv[] ), ma possono rilevare la lunghezza di quell'array o se qualcosa di inaspettato si trova o meno nella posizione dell'array errata. grep non lo fa e accetta più file, che è in base alla progettazione.

Correlati:dopo l'aggiornamento a Ubuntu 13.10, Firefox a volte si blocca il computer?

Nella nota a margine, la citazione impropria unita al globbing con grep a volte può essere un problema. Considera questo:

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 utente non preparato si aspetterebbe che grep corrisponda a qualsiasi riga con est lettere in esso provenienti da pipe, ma invece l'espansione del nome file della shell ha distorto tutto. Ho visto questo succedere spesso con persone che fanno ps aux | grep shell_script_name.sh e si aspettano di trovare il loro processo in esecuzione, ma perché hanno eseguito il comando dalla stessa directory in cui si trovava lo script , l'espansione del nome del file della shell è stata eseguita grep comando per apparire dietro le quinte completamente diverso da quello che l'utente si aspettava.

Il modo corretto sarebbe usare le virgolette singole:

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. Come usare il comando Linux grep

  2. Come eseguire un comando memorizzato in una variabile?

  3. Come eseguire un comando quando il contenuto di una directory viene aggiornato?

  4. Come funziona il comando Tee?

  5. In che modo il comando Xdg-open sa quale applicazione utilizzare per aprire un file?

COME USARE IL COMANDO TAIL

Come usare il comando head

Come usare grep in Linux

Come gestire gli snap in Linux – Parte 2

Cosa fa il comando Startx?

Che cos'è il comando Grep in Linux? Perché viene utilizzato e come funziona?