Qual è la differenza tra a[bc]d
e a{b,c}d
? Perché le persone usano a{b,c}d
quando c'è già a[bc]d
?
ls
e provi solo singoli caratteri, sembrerebbero funzionare allo stesso modo.
Qual è la differenza tra a[bc]d
e a{b,c}d
? Perché le persone usano a{b,c}d
quando c'è già a[bc]d
?
ls
e provi solo singoli caratteri, sembrerebbero funzionare allo stesso modo.
Risposte:
I due sono abbastanza diversi.
a[bc]d
è un modello di nome file (in shell diverse da fish
). Si espanderà ai due nomi di file abd
e acd
se quelli sono nomi di file esistenti nella directory corrente.
La [...]
parte è un'espressione tra parentesi che corrisponde a un singolo carattere tra quelli elencati (o elementi di confronto quando gli intervalli sono inclusi). Per abbinare il modello a[bc]d
, il carattere tra le stringhe a
e d
in un nome file deve essere a b
o a c
.
Se abd
esiste, ma acd
non lo è, si espanderà solo abd
e viceversa.
Se nessuno dei due abd
, né acd
esistere, a seconda del guscio e delle opzioni, si innescherebbe un errore (originale Unix sh
, (t)csh
, zsh
, fish
, bash -O failglob
) ed eventualmente uscire dalla shell, o lasciare l'unexpanded¹ modello (Bourne-like e rc
-come conchiglie) o espandere a niente ( bash/zsh/yash -o nullglob
, alcune versioni precedenti di fish
, Unix originale sh
e (t)csh
se ci sono altri glob corrispondenti nello stesso comando).
a{b,c}d
è un'espansione di parentesi graffe (in shell che supportano queste). Si espanderà alle due stringhe abd
e acd
.
La {...}
parte è un insieme di stringhe delimitate da virgole (in questo esempio; in alcune shell, può anche essere un intervallo come a..k
o 20..25
o più avanzate come 00..20..2
o 0..20..2%02d
) e l'espansione viene calcolata combinando ciascuna di queste stringhe con il fianco stringhe a
e d
. Queste stringhe potrebbero essere più lunghe di un singolo personaggio e potrebbero essere anche loro stesse espansioni.
L'espansione avviene indipendentemente dal fatto che queste stringhe corrispondano o meno ai nomi di file esistenti.
Se stai costruendo stringhe, usa un'espansione di controvento. Se si corrispondono nomi di file, utilizzare un modello di nome file.
¹ In questo caso particolare, a[bc]d
potrebbe capitare di essere il nome di un file esistente, motivo per cui è potenzialmente pericoloso usare cose come rm -f ./*.[ch]
quelle shell ed rm -f ./*.{c,h}
è meno problematico.
a{b,c}d
, le parti b
e c
non devono essere lettere singole; es ex{ten,ci}sion
. Mentre ex[tenci]sion
o qualunque cosa corrisponderà solo a una di queste lettere.
a[bc]d
corrisponde al modello ed è parte dello standard POSIX. In POSIX, questo viene introdotto come "espressione parentesi di modello". È documentato nella sezione 2.13 del manuale
Se non quotati e al di fuori di un'espressione di parentesi quadre, i seguenti tre caratteri devono avere un significato speciale nella specifica dei modelli:
?
Un punto interrogativo è un modello che deve corrispondere a qualsiasi carattere.
*Un asterisco è un modello che deve corrispondere a più caratteri, come descritto in Modelli che corrispondono a più caratteri.
[La parentesi aperta deve presentare un'espressione di parentesi quadre.
La sezione 2.13.3 menziona anche qualcosa che si comporta in modo diverso da quello che ci si aspetterebbe dalle solite regex quando viene utilizzato per l'espansione del nome file (enfasi da me)
Le regole descritte finora in Pattern corrispondenti a un singolo carattere e Pattern corrispondenti a più caratteri sono qualificati dalle seguenti regole che si applicano quando viene utilizzata la notazione di corrispondenza dei pattern per l'espansione del nome file:
Il carattere barra in un percorso deve essere abbinato esplicitamente usando una o più barre nel modello; non deve essere associato all'asterisco o ai caratteri speciali del punto interrogativo né a un'espressione tra parentesi. Le barre nella sequenza devono essere identificate prima delle espressioni tra parentesi; pertanto, una barra non può essere inclusa in un'espressione di parentesi di modello utilizzata per l'espansione del nome file. Se viene trovato un carattere barra dopo un carattere di parentesi quadra aperta senza escape prima che venga trovata una parentesi quadra di chiusura corrispondente, la parentesi aperta deve essere trattata come un carattere ordinario. Ad esempio, il modello
"a[b/c]d"
non corrisponde a nomi di percorso comeabd
oa/d
. Corrisponde letteralmente solo a un nome percorsoa[b/c]d
.
a{b,c}d
è espansione di parentesi graffe , non è nelle specifiche di POSIX. Ecco la parte corrispondente dal manuale di bash (enfasi da me):
L'espansione del controvento è un meccanismo mediante il quale è possibile generare stringhe arbitrarie . Questo meccanismo è simile all'espansione del nome file (vedere Espansione nome file), ma i nomi file generati non devono necessariamente esistere . I pattern da ampliare assumono la forma di un preambolo opzionale , seguito da una serie di stringhe separate da virgola o da un'espressione di sequenza tra una coppia di parentesi graffe, seguita da un poscritto opzionale . Il preambolo è preceduto da ciascuna stringa contenuta tra parentesi graffe e il post script è quindi aggiunto a ciascuna stringa risultante, espandendosi da sinistra a destra.
Secondo il commento di @mosvy, questo è apparso per la prima volta, csh
ma il comportamento bash
è diverso da csh
e altri gusci. Questo tipo di espansione delle parentesi graffe è anche presente in glob(3)
.
Esiste un altro tipo di espansione delle parentesi graffe {a..z}
che è apparso solo dopo bash
3.0 e ne sono stati aggiunti altri in bash
4.0.
In una shell in cui è attivato il globbing, eseguire in una cartella vuota, viene restituito il seguente risultato
$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd
In risposta al commento di @Jesse_b, se ci si trova in una shell interattiva ed entrambi si applicano, a[bc]d
è meno difficoltà a digitare. Per esempio grep pattern [ab][12].txt
.
csh
, molto prima bash
. È anche presente nella funzione libreria glob (3). La differenza è che bash
viene eseguita prima di altre espansioni: a=A; ab=A/B; ac=A/C; echo $a{b,c}
funzionerà in bash in modo diverso da qualsiasi altra shell.
command a[bc]d
?