Storia di Bash globbing


11

C'è un motivo storico per cui Bash "palpitante" ed espressioni regolari non sono identici? Ad esempio, credo che in Bash [1-2]*corrisponda a tutto ciò che inizia con 1 o 2 seguito da qualsiasi altra cosa, mentre come espressione regolare [1-2]*corrisponderebbe solo a una sequenza di 1 e 2 secondi. I miei script Bash e REGEX foo sono entrambi piuttosto deboli e mi imbatto regolarmente in problemi associati a queste differenze che mi hanno incuriosito sul perché sono diversi.


3
Considereresti di fare rm -- ^[^.].*\.txt$invece di rm -- *.txt?
Stéphane Chazelas,

1
Gran parte delle tue Q sono toccate in questo thread da lwn: lwn.net/Articles/96687
slm

Ci sono comandi che operano su nomi di file e accettano regexp. Ad esempio find, find . -regex ".*\.txt$" | xargs rm --o renameper rinominare i file (è sedper i nomi dei file), attenzione che alcuni sistemi ne abbiano uno diverso rename.
ctrl-alt-delor,

@richard, dovevo ^[^.].*\.txt$prendere in considerazione l'ignoranza dei file dot. Si noti che la -regexè un'estensioni GNU, alcune conchiglie come ksh93 o zsh possono incorporare nelle loro espressioni regolari globs (provare per esempio: ksh93 -c 'echo ~(E:^[^.].*\.txt$)')
Stéphane Chazelas

2
Quella bash segue così attentamente la pratica esistente, evitando cambiamenti ed estensioni incompatibili in modo incompatibile è uno dei suoi maggiori punti di forza.
ormaaj,

Risposte:


12

bashè stato inizialmente progettato alla fine degli anni '80 come un clone parziale di kshcon alcune funzionalità interattive di csh / tcsh.

Le origini del globbing devono essere trovate in quelle precedenti conchiglie su cui si basa.

kshdi per sé è un'estensione della shell Bourne. La stessa shell Bourne (rilasciata per la prima volta nel 1979 in Unix V7) era un'implementazione pulita da zero, ma non si discostava completamente dalla shell Thompson (la shell di V1 -> V6) e incorporava funzionalità della shell Mashey.

In particolare, gli argomenti di comando erano ancora separati da spazi, |ora era il nuovo operatore pipe ma ^era ancora supportato come alternativa (e spiega anche perché lo fai [!a-z]e non [^a-z]), $1era ancora il primo argomento di uno script e la barra rovesciata era ancora il carattere di escape . Quindi molti operatori regexp ( ^\|$) hanno un significato speciale nella shell.

La shell Thompson si basava su un'utilità esterna per il globbing. Se shtrovato non quotato *, [o ?s nel comando, eseguirà il comando attraverso glob.

rm *.txt

finirebbe per girare glob come:

["glob", "rm", "*.txt"]

e glob sarebbe finito rmcon l'elenco dei file corrispondenti a quel modello.

grep a.\*b *.txt

sarebbe eseguito globcome:

["glob", "grep", "a.\252b", "*.txt"]

Quanto *sopra è stato citato impostando l'ottavo bit su quel personaggio, impedendo globdi trattarlo come un jolly. globrimuoverebbe quel bit prima di chiamare grep.

Per fare l'equivalente con regexps, sarebbe stato:

regexp rm '\.txt$'

O:

regexp rm '^[^.].*\.txt$'

per escludere file dot.

La necessità di sfuggire agli operatori mentre si raddoppiano come caratteri speciali della shell, il fatto che ., comune nei nomi dei file sia un operatore regexp, non è molto appropriato per abbinare i nomi dei file e complicato per un principiante. Nella maggior parte dei casi, tutto ciò che serve sono i caratteri jolly che possono sostituire uno ( ?) o qualsiasi numero ( *) di caratteri.

Ora, conchiglie diverse hanno aggiunto diversi operatori globbing. Al giorno d'oggi, i globs ksh e zsh (e in una certa misura bash -O extglobche implementano un sottoinsieme di globi ksh) sono funzionalmente equivalenti a regexps con una sintassi che è meno ingombrante da usare con i nomi dei file e l'attuale sintassi della shell. Ad esempio, in zsh(con estensione extendedglob), puoi fare:

echo a#.txt

se si desidera (improbabile) corrispondere a nomi di file costituiti da sequenze aseguite da .txt. Più facile di echo (^a*\.txt$)(qui usando le parentesi graffe come un modo per isolare gli operatori regex dagli operatori di shell che avrebbero potuto essere un modo in cui le shell potevano gestirlo).

echo (foo|bar|<1-20>).(#i)mpg

Per file mpg (senza distinzione tra maiuscole e minuscole) il cui nome base è pippo, barra o un numero decimale compreso tra 1 e 20 ...

ksh93ora può anche incorporare regexps (base, estesa, perl-like o "aumentata") nei suoi globs (anche se è piuttosto buggy) e persino fornire uno strumento per convertire tra glob e regexp ( printf %R, printf %P):

echo ~(Ei:.*\.txt)

a partita (non nascosto) file txt con E Xtended le espressioni regolari, tra maiuscole i nsensitively.


Fantastico scrivere! In realtà non è possibile utilizzare ~(opt:pat)per nessuna delle opzioni in maiuscolo. Forse print -r -- ~(Ei).*\.txt$. Inserire il motivo all'interno sembra essere utile solo per evitare di attivare o disattivare un'opzione per parte di un motivo. Stranamente puoi mescolare e abbinare più linguaggi di pattern all'interno dello stesso glob. ~(Ki)*.~(E)txt$è equivalente. (Alla fine tutto viene semplicemente convertito in regex e passato internamente al motore regex di libast).
ormaaj,

@ormaaj, ~(Ei:.*\.txt)funziona per me anche con versioni di 15 anni come ksh93 o +.
Stéphane Chazelas,

Funziona anche con uno dei miei binari di prova salvati (24-12-2014), ma ricordo di essermi imbattuto in problemi con quello. Le cose erano sempre casualmente rotte e riparate di nuovo tra le versioni quando ksh era ancora commercialmente sviluppato. Ricordo che il codice di corrispondenza dei modelli era una delle aree fragili.
ormaaj,

@ormaaj, uno diverso tra ~(E)xe ~(E:x)è che il secondo è ancorato (corrisponde xsolo mentre il primo corrisponde su qualsiasi cosa contenga x), che potrebbe essere il tipo di problema che hai riscontrato (usare ~(-lr)~(E:x)per rimuovere l'ancoraggio, ~(E-lr:x)non lo farà). In ogni caso, concordo sul fatto che è piuttosto buggy, anche nell'ultima versione.
Stéphane Chazelas,

9

Le lingue regolari furono introdotte da Kleene nel 1956. Il documento seminale non aveva la notazione moderna completa per le espressioni regolari, ma introdusse la "stella di Kleen": che A*significa "qualsiasi numero di ripetizioni di A". Nel prossimo decennio sono emerse alcune notazioni più o meno standard, in particolare .per un carattere arbitrario e ?per indicare che il carattere precedente è facoltativo.

La notazione globbing di Bash deriva dal globcomando introdotto completamente in Unix v1 nel 1971. All'epoca, il globbing era eseguito da un programma separato; è stato successivamente spostato nel guscio. Il globcomando iniziale deve ?significare "qualsiasi carattere" e *"qualsiasi sequenza di caratteri". Non so perché i personaggi sono stati scelti; ?è piuttosto intuitivo e *potrebbe essere stato ispirato da quello delle espressioni regolari.

Globbing non intendeva essere generale come le espressioni regolari, e le espressioni regolari non erano molto diffuse al momento, quindi non vi era alcuna chiamata a unificare i concetti. Fin dall'inizio, c'erano incompatibilità sintattiche, con ?, .e *che significa cose diverse in modelli di nomi di file e nelle espressioni regolari.

Conchiglie moderne come bash si espandono su modelli glob, ma è stata un'evoluzione graduale a mantenere la compatibilità con le versioni precedenti. Ksh88 (la versione del 1988 della shell Korn ) introdusse una sintassi estesa per i modelli di shell, che non poteva essere la stessa sintassi delle normali espressioni regolari ma ne fu fortemente ispirata: *(PATTERN)per indicare un numero qualsiasi di ripetizioni di PATTERN, @(PATTERN1|PATTERN2)per dire " PATTERN1o PATTERN2", eccetera.

Le versioni moderne di bash (dalla 2.02) supportano gli schemi estesi di ksh88, se si rilascia per shopt -s extglobprimi.


Bash non ha mai supportato extglobs? Per quanto ne so, Bash, zsh e {pd, m} ksh hanno supportato esattamente gli stessi globs documentati nel manuale di ksh88 sin dai primi giorni. Ksh fino ad oggi non ha nemmeno un'opzione per disabilitare quantificatori glob "estesi", e ksh93 è l'unico del gruppo ad avere estensioni oltre a ciò che aveva ksh88.
ormaaj,

2
@ormaaj Ksh88 ha esteso i globs e l' extglobopzione è stata introdotta nella bash 2.02 da qualche parte intorno al 1998. Zsh ha acquisito ksh_globla serie 3.1 da qualche parte nello stesso periodo. Zsh ha molte estensioni a sé stanti (alcune richiedono l' extended_globopzione).
Gilles 'SO- smetti di essere malvagio' il

Vedo. Quindi in realtà era abbastanza tardi per giustificare la necessità di un'opzione. (Penso che il default sia disattivato in questi giorni ma è inutile, ma interessante.)
ormaaj

1
@ormaaj, Nota che bash, contrariamente a ksh, extglob rende bash non conforme a POSIX perché non è disabilitato nelle variabili. In ksh, si var='@(*)'; echo $varespande a tutti i nomi di file nella directory corrente che iniziano @(e finiscono )come POSIX richiede mentre in bash -O extglobessa si espande a tutti i file. (tuttavia, si potrebbe considerare che il comportamento bash ha più senso qui (e il comportamento ksh è piuttosto doloroso quando si desidera avere schemi nelle variabili)). La sintassi globale è così imbarazzante a causa di ciò (compatibilità POSIX / Bourne). Confronta con globi estesi zsh.
Stéphane Chazelas,

@ StéphaneChazelas È tutto vero, e mi piace come ksh sia in qualche modo intelligente. Raramente entra in gioco anche se a meno che non sia effettivamente vincolato a POSIX. Con quasi ogni uso per il wordplitting sostituito da funzionalità migliori e la memorizzazione di schemi in variabili è comunque un disturbo estremo poiché devi svuotare l'IFS, disabilitare l'espansione del controvento ovunque ma bash. Penso che sia ancora impossibile essere completamente al sicuro con i modelli memorizzati. Ad esempio, questo vecchio problema di fuga non è mai stato realmente risolto.
ormaaj,

1

Motivo storico: SÌ. Riferimento:
http://en.wikipedia.org/wiki/Glob_(programming)#Origin

Giusto per mostrare la divergenza, ecco un buon esempio: a*

  • shell globbing: il significato è, il primo personaggio è ae poi qualunque cosa (a, ab, abca ...)
  • regex: significato è, zero o più ripetizioni di carattere a(a, aa, aaa ...)

Concordo prontamente sul fatto che questa discrepanza di significato sia molto confusa per i nuovi utenti.

Il globbing è forse più facile da comprendere per i nuovi arrivati, ma è anche un costrutto meno potente.

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.