Come si salva un regex complesso per il riutilizzo multiplo in sed?


12

Usando sed, creo spesso regex piuttosto complicati e intricati che devo abbinare due volte in un file. C'è un modo per salvare questo regex e fare riferimento due volte?

Forse qualcosa che assomiglia a questo?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

Aggiornamento: una risposta ha presentato la soluzione dell'utilizzo di una variabile bash. Questo non funziona Dato a test.txt.

#test.txt
foo bar
bar foo

E la sceneggiatura

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

Questo dovrebbe produrre l'output

foo happy bar
bar foo

Ma invece ottengo l'errore

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS

Se usi Perl, puoi fare riferimento a parti precedenti dell'espressione all'interno dell'espressione:perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
glenn jackman,

1
Quando trovi qualcosa di troppo complicato per sed, non esitare a cercare awk o perl.
Gilles 'SO- smetti di essere malvagio' il

2
@Cory: il tuo esempio funziona benissimo, se ottieni la sua sintassi corretta. Hai la "variabile $" ancora racchiusa tra "virgolette singole" che la nasconde dall'espansione della shell che ti aspetti ... dovrebbe esseresed 's/'"${VALUE}"'/foo happy \1/' test.txt
Peter.O

Risposte:


7

Puoi usare le variabili della shell:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

Non sono sicuro di cosa intendevi dire $i, ma potresti aver bisogno di metterlo al di fuori delle virgolette singole:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'

Naturalmente questo funziona solo se il sedcomando viene invocato dalla shell, ma esiste una soluzione simile con quasi tutti i linguaggi di programmazione. (E non credo sia possibile usare le variabili all'interno sed.)
Stéphane Gimenez,

Hrm. Provando questo, le backreferenze sembrano essere rotte. s/$complicated_regex/\1/dà un errore dicendo che è un riferimento non valido.
Cory Klein,

Ah, forse è colpa mia, sono abituato alle sostituzioni di variabili zsh. Vedi la risposta aggiornata.
Stéphane Gimenez,

Dovrai rimuovere le ancore dalla variabile e inserirle nello script sed:sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
glenn jackman,

Duh! Sì, ho dimenticato di verificare che mi sia stata concessa una concatenazione regex valida :-)
Stéphane Gimenez,

0

Il modo più semplice per inserire il valore di una variabile shell sede non preoccuparsi di come il backslash-escape dovrà cambiare per il resto dello sedscript, è mettere tutto in virgolette singole tranne la variabile e metterlo tra virgolette doppie.

Tutti i seguenti esempi di codice presuppongono: VALUE='foo \([a-z]\+\)'

Il seguente rotto codice non riesce perché la variabile VALUEnon è espanso:

sed 's/"${VALUE}"/foo happy \1/' test.txt

Il seguente rotto il codice non riesce perché la barra rovesciata sul \1viene mangiato dalla shell (perché è tra virgolette, anziché virgolette singole), prima sedmai lo vede:

sed "s/${VALUE}/foo happy \1/" test.txt

Il seguente codice funziona come previsto:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

Anche il seguente codice funziona:

sed "s/${VALUE}/foo happy \\1/" test.txt

Quindi fa quanto segue:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

Ma perché complicarsi? Le virgolette singole intorno a uno sedscript rendono tutto molto più chiaro, specialmente per i guru non shell-scripting che leggono il tuo codice. Il mio modo preferito è, ancora una volta, abbandonare le virgolette singole per raddoppiare le virgolette solo per l'espansione variabile e tornare indietro alle virgolette singole:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
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.