Qual è la differenza tra `a [bc] d` (parentesi) e` a {b, c} d` (parentesi graffe)?


28

Qual è la differenza tra a[bc]de a{b,c}d? Perché le persone usano a{b,c}dquando c'è già a[bc]d?


Chi ti ha detto di usare command a[bc]d?
Jesse_b

3
Certamente ha i suoi usi se uno lo capisce correttamente.
Weijun Zhou,

7
Immagino di non capire come sia avvenuta la confusione tra i due.
Jesse_b

Mi è stato chiesto esplicitamente da un collega che non ha familiarità con Linux su questo, sebbene non di recente.
Weijun Zhou,

@Jesse_b Se le provassi solo con operazioni su file simili lse provi solo singoli caratteri, sembrerebbero funzionare allo stesso modo.
Nacht - Ripristina Monica il

Risposte:


43

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 acdse 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 ae din un nome file deve essere a bo a c.

  • Se abdesiste, ma acdnon lo è, si espanderà solo abde viceversa.

  • Se nessuno dei due abd, né acdesistere, 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 she (t)cshse 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..ko 20..25o più avanzate come 00..20..2o 0..20..2%02d) e l'espansione viene calcolata combinando ciascuna di queste stringhe con il fianco stringhe ae 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]dpotrebbe 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.


Grazie per aver chiarito "Se abd esiste, ma acd no, allora si espanderebbe solo in abd". Immagino sia quello che manca alla mia risposta.
Weijun Zhou,

9
Un'altra differenza cruciale è che in a{b,c}d, le parti be cnon devono essere lettere singole; es ex{ten,ci}sion. Mentre ex[tenci]siono qualunque cosa corrisponderà solo a una di queste lettere.
alexis

7

a[bc]dcorrisponde 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 come abdo a/d. Corrisponde letteralmente solo a un nome percorso a[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, cshma il comportamento bashè diverso da cshe 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 bash3.0 e ne sono stati aggiunti altri in bash4.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.


2
L'espansione del tutore non è un "bashismo"; è apparso per la prima volta csh, molto prima bash. È anche presente nella funzione libreria glob (3). La differenza è che bashviene 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.
mosvy,

Grazie. Aggiornerò la risposta.
Weijun Zhou,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.