*
ha uno speciale significato sia come un guscio globbing carattere ( "jolly") e come un normale espressione metacarattere . È necessario prendere in considerazione entrambi, anche se se si cita la propria espressione regolare, è possibile impedire alla shell di trattarla in modo speciale e assicurarsi che la passi invariata grep
. Sebbene sorta di simile concettualmente, quale *
mezzo per il guscio è molto diverso da quello che significa grep
.
Innanzitutto la shell considera *
un jolly.
Tu hai detto:
Il fatto che l'espressione sia racchiusa tra virgolette non fa differenza.
Dipende da quali file esistono in qualunque directory ci si trovi quando si esegue il comando. Per i modelli che contengono il separatore di directory /
, può dipendere da quali file esistono nell'intero sistema. Dovresti sempre citare espressioni regolari per grep
- e le virgolette singole sono in genere le migliori - a meno che tu non sia sicuro di stare bene con i nove tipi di trasformazioni potenzialmente sorprendenti che altrimenti la shell esegue prima di eseguire il grep
comando.
Quando la shell incontra un *
carattere che non è citato , significa che significa "zero o più di qualsiasi carattere" e sostituisce la parola che lo contiene con un elenco di nomi di file che corrispondono al modello. (I nomi di file che iniziano con .
sono esclusi - a meno che il modello stesso non inizi con .
o non abbia configurato la shell per includerli comunque.) Questo è noto come globbing - e anche dall'espansione del nome del file e dell'espansione del percorso .
L'effetto di grep
solito è che il primo nome del file corrispondente viene preso come l'espressione regolare - anche se sarebbe abbastanza ovvio a un lettore umano che è non è inteso come un'espressione regolare - mentre tutti gli altri nomi di file elencati automaticamente dal tuo i glob vengono presi come file all'interno dei quali cercare le corrispondenze. (Non vedi la lista - è passata opacamente a grep
.) Praticamente non vuoi che ciò accada.
Il motivo di questo è a volte non è un problema - e nel suo caso particolare, almeno fino ad ora , non't - è che *
sarà lasciato solo se tutte le seguenti condizioni :
C'erano nessun file i cui nomi abbinati. ... O hai disabilitato il globbing nella tua shell, in genere con set -f
o equivalente set -o noglob
. Ma questo è raro e probabilmente sapresti di averlo fatto.
Stai usando una shell il cui comportamento predefinito è lasciare *
da solo quando non ci sono nomi di file corrispondenti. Questo è il caso di Bash, che probabilmente stai usando, ma non in tutte le shell in stile Bourne. (Il comportamento predefinito nella popolare shell Zsh, ad esempio, è per globs di (a) espandere o (b) produrre un errore.) ... O hai cambiato questo comportamento della tua shell - come ciò varia attraverso le conchiglie.
Altrimenti non hai detto alla tua shell di consentire la sostituzione dei globs con nulla quando non ci sono file corrispondenti, né di fallire con un messaggio di errore in questa situazione. In Bash ciò sarebbe stato possibile abilitando l' opzionenullglob
o failglob
shell , rispettivamente.
A volte puoi fare affidamento su # 2 e # 3 ma raramente puoi fare affidamento su # 1. Un grep
comando con un modello non quotato che funziona ora potrebbe smettere di funzionare quando si hanno file diversi o quando lo si esegue da una posizione diversa. Cita la tua espressione regolare e il problema scompare.
Quindi il grep
comando considera *
un quantificatore.
Le altre risposte - come quelle di Sergiy Kolodyazhnyy e di Kos - affrontano anche questo aspetto di questa domanda, in modi leggermente diversi. Quindi incoraggio coloro che non li hanno ancora letti a farlo, prima o dopo aver letto il resto di questa risposta.
Supponendo che lo *
faccia fare grep - che la quotazione dovrebbe garantire - grep
quindi lo porta a significare che l'elemento che lo precede può accadere un numero qualsiasi di volte , piuttosto che dover ricorrere esattamente una volta . Potrebbe ancora succedere una volta. O potrebbe non essere presente affatto. O potrebbe essere ripetuto. Il testo che si adatta a una di queste possibilità verrà adattato.
Cosa intendo per "oggetto"?
Un singolo personaggio . Poiché b
partite letterale b
, b*
zero o più b
s, quindi ab*c
partite ac
, abc
, abbc
, abbbc
, etc.
Allo stesso modo, dal momento che .
qualsiasi carattere , .*
corrisponde a zero o più caratteri 1 , quindi a.*c
partite ac
, akc
, ahjglhdfjkdlgjdfkshlgc
, anche acccccchjckhcc
, ecc Or
Una classe di personaggi . Poiché [xy]
partite x
o y
, [xy]*
zero o più caratteri dove ciascuno è o x
o y
, quindi p[xy]*q
partite pq
, pxq
, pyq
, pxxq
, pxyq
, pyxq
, pyyq
, pxxxq
, pxxyq
, etc.
Questo vale anche per stenografia forme di classi di personaggi come \w
, \W
, \s
, e \S
. Poiché \w
corrisponde a qualsiasi carattere di parola, \w*
corrisponde a zero o più caratteri di parole. O
Un gruppo . Dal momento che \(bar\)
le partite bar
, \(bar\)*
zero o più bar
s, quindi foo\(bar\)*baz
partite foobaz
, foobarbaz
, foobarbarbaz
, foobarbarbarbaz
, etc.
Con le opzioni -E
o -P
, grep
tratta la tua espressione regolare come rispettivamente ERE o PCRE , piuttosto che come BRE , e quindi i gruppi sono circondati (
)
invece di \(
\)
, quindi useresti (bar)
invece di \(bar\)
e foo(bar)baz
invece di foo\(bar\)baz
.
man grep
fornisce una spiegazione ragionevolmente accessibile della sintassi BRE ed ERE alla fine, oltre a elencare tutte le opzioni della riga di comando grep
accettate all'inizio. Raccomando quella pagina di manuale come risorsa, e anche la documentazione GNU Grep e questo tutorial / sito di riferimento (che ho collegato a un numero di pagine sopra, sopra).
Per i test e l'apprendimento grep
, ti consiglio di chiamarlo con uno schema ma senza nome file. Quindi prende l'input dal tuo terminale. Inserisci le righe; le righe che ti fanno eco sono quelle che contenevano il testo corrispondente al tuo motivo. Per uscire, premere Ctrl+ Dall'inizio di una riga, che segnala la fine dell'ingresso. (Oppure puoi premere Ctrl+ Ccome con la maggior parte dei programmi da riga di comando.) Ad esempio:
grep 'This.*String'
Se usi la --color
bandiera, grep
evidenzierai le parti specifiche delle tue linee che corrispondono alla tua espressione regolare, il che è molto utile sia per capire cosa fa un'espressione regolare sia per trovare quello che stai cercando una volta che lo fai. Per impostazione predefinita, gli utenti di Ubuntu hanno un alias Bash che provoca grep --color=auto
l'esecuzione - il che è sufficiente per questo scopo - quando si esegue grep
dalla riga di comando, quindi probabilmente non è nemmeno necessario passare --color
manualmente.
1 Pertanto, .*
in un'espressione regolare significa cosa *
significa in un guscio glob. Tuttavia, la differenza è che grep
stampa automaticamente le linee che contengono la tua corrispondenza ovunque in esse, quindi in genere non è necessario avere .*
all'inizio o alla fine di un'espressione regolare.
* != any number of unknown characters
leggi il documento.)