Perché devo sfuggire ai personaggi regex in sed per essere interpretati come personaggi regex?


11

Sembra ad esempio
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
che io devo scappare personaggi per formare un'espressione regolare. In questo caso ho dovuto sfuggire alle parentesi graffe per essere interpretato più volte.
Perché? Mi aspettavo che tutto sarebbe stato un personaggio regex se non fosse sfuggito. Cioè il contrario.


C'era un post sulla ricerca in Vim che in qualche modo copre questa domanda, la versione breve è "dipende dall'implementazione del comando" ... unix.stackexchange.com/questions/90345/…
Drav Sloan

@DravSloan: non sono sicuro che sia lo stesso. In Vim cerchi il testo per impostazione predefinita e devi scappare per cercare regex, ma in questo caso il formato si aspettas/regex//g già una regex e mi aspetto che sia il testo che avrebbe bisogno essere evaso
Jim,

Risposte:


14

Questo perché sedutilizza POSIX BRE (espressioni regolari di base) al contrario delle ERE (espressioni regolari estese) a cui probabilmente sei abituato da Perl o dagli amici.

Dalla sed(1)pagina man:

REGULAR EXPRESSIONS
       POSIX.2 BREs should be supported, but they aren't completely because of
       performance problems.  The \n sequence in a regular expression  matches
       the newline character, and similarly for \a, \t, and other sequences.

Citazione pertinente dal link sopra:

Le espressioni regolari di base o il sapore BRE standardizzano un sapore simile a quello usato dal comando grep UNIX tradizionale. Questo è praticamente il più antico sapore di espressione regolare ancora in uso oggi. Una cosa che distingue questo sapore è che la maggior parte dei metacaratteri richiede una barra rovesciata per conferire al metacarattere il suo sapore. La maggior parte degli altri gusti, incluso POSIX ERE, usa una barra rovesciata per sopprimere il significato dei metacaratteri.

Citato alla lettera dal commento di Craig Sanders :

Nota che almeno in GNU sed puoi dire a sed di usare regexps estesi con l'opzione della riga di comando -r o --regexp-extended. Ciò è utile se si desidera evitare di bruciare il proprio script sed con una fuga eccessiva.


1
Nota che almeno in GNU sed puoi dire a sed di usare regexps estesi con l' opzione della riga di comando -ro --regexp-extended. Ciò è utile se si desidera evitare di bruciare il proprio script sed con una fuga eccessiva.
CAS

@CraigSanders Grazie per questo. Aggiunto per rispondere.
Joseph R.,

@CraigSanders, altre sedimplementazioni (quando supportano ERE, principalmente BSD) tendono invece a usarle -E(il che ha molto più senso dato che è la stessa opzione di grep. Perché GNU ha sedscelto -rè un mistero per me).
Stéphane Chazelas,

sì, un mistero anche per me. Avrebbe più senso usare -E. e quindi aggiungi -F, -G e -P per abbinare GNU grep. IMO gawk trarrebbe beneficio anche dagli stessi argomenti di RE ... o almeno, -P.
Cas

12

Questo per motivi storici.

Regexp fu introdotto per la prima volta in Unix ednell'utility nei primi anni '70. Sebbene edsi basava su qedcui attuazione dagli stessi autori capito regexp più complesso, edcompreso solo ^, $, [...], ., *e \per sfuggire tutto quanto sopra.

Ora, quando è emersa la necessità di avere più operatori, è stato necessario trovare un modo per introdurli senza interrompere la compatibilità con le versioni precedenti. Se uno script usasse il s edcomando s/foo() {/foo (var) {/gper sostituire tutte le istanze di foo() {with foo(var) { e tu avessi introdotto un operatore (o {, questo lo spezzerebbe.

Tuttavia nessuno script lo farebbe s/foo\(\) {/foo\(var\) {/, perché è lo stesso di s/foo() {/foo(var) {/e non c'era motivo di scappare (perché non era un operatore RE. Quindi l'introduzione di un nuovo operatore \(o \{non interrompe la retrocompatibilità poiché è molto improbabile che si rompa uno script esistente usando la sintassi precedente.

Quindi, ecco cosa è stato fatto. Successivamente, è \(...\)stato aggiunto inizialmente solo per il s edcomando di fare cose simili s/foo\(.\)/\1bar/e successivamente come grep '\(.\)\1'(ma non cose simili \(xx\)*).

In UnixV7 (1979, quindi quasi un decennio più tardi), una nuova forma di espressioni regolari è stata aggiunta nel nuovo egrepe le awkutilità chiamate espressioni regolari estese (poiché sono nuovi strumenti, non c'è compatibilità con le versioni precedenti da rompere). Alla fine, ha fornito la funzionalità disponibile nell'antico Ken Thompson qed(operatore di alternanza |, raggruppamento (..)*) e ha aggiunto alcuni operatori come +e ?(ma non aveva la funzione di backref delle espressioni regolari di base).

Successivamente i BSD hanno aggiunto \<e \>(sia a BRE che a ERE) e SysV aggiunti \{e \}solo a BRE.

Non è molto tempo dopo {e }sono stati aggiunti a ERE, con una tale retrocompatibilità. Non tutti l'hanno aggiunto. Ad esempio, GNU awkfino alla versione 4.0.0 (2011) non supportava a {meno che non fosse forzato nella modalità di conformità POSIX.

quando GNU grepfu scritto nei primi anni '90, aggiunse tutte le chicche di BSD e SysV (come \<, {) e invece di avere due sintassi regexp separate e motore per BRE ed ERE, implementò gli stessi operatori in entrambi, solo le controparti BRE di (, ?, {, +devono essere preceduti da una barra rovesciata (per essere compatibile con altre implementazioni BRE). Ecco perché puoi farlo .\+in GNU grep(anche se non è POSIX o supportato da altre implementazioni) e puoi farlo (.)\1in GNU egrep(anche se non è POSIX o supportato da molte altre implementazioni tra cui GNU awk).

L'aggiunta di \xoperatori non è l'unico modo per aggiungere più operatori in modo compatibile con le versioni precedenti. Ad esempio, perlusato (?...). È ancora compatibile con le ERE all'indietro in quanto (?=...)non è valido nelle ERE, lo stesso per .*?. vimper operatori simili ha fatto diversamente introducendo \@=o .\{-}per esempio.

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.