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