GNU/Linux >> Linux Esercitazione >  >> Linux

Come assicurarsi che la stringa interpolata nella sostituzione `sed` sfugga a tutti i metachar?

Ho uno script che legge un flusso di testo e genera un file di comandi sed che viene successivamente eseguito con sed -f . I comandi sed generati sono come:

s/cid:[email protected]/https://mysite.com/files/1922/g
s/cid:[email protected]/https://mysite.com/files/1923/g
s/cid:[email protected]/https://mysite.com/files/1924/g

Assumere lo script che genera il sed comandi è qualcosa del tipo:

while read cid fileid
do
    cidpat="$(echo $cid | sed -e s/\./\\./g)"
    echo 's/'"$cidpat"'/https://mysite.com/files/'"$fileid"'/g' >> sedscr
done

Come posso migliorare lo script per garantire tutti i metacaratteri regex nel cid le stringhe sono state salvate e interpolate correttamente?

Risposta accettata:

Per sfuggire alle variabili da utilizzare sul lato sinistro e destro di una s comando in sed (qui $lhs e $rhs rispettivamente), faresti:

escaped_lhs=$(printf '%sn' "$lhs" | sed 's:[][\/.^$*]:\&:g')
escaped_rhs=$(printf '%sn' "$rhs" | sed 's:[\/&]:\&:g;$!s/$/\/')

sed "s/$escaped_lhs/$escaped_rhs/"

Nota che $lhs non può contenere un carattere di nuova riga.

Cioè, sull'LHS, esegui l'escape di tutti gli operatori regexp (][.^$* ), il carattere di escape stesso ( ) e il separatore (/ ).

Su RHS, devi solo sfuggire a & , il separatore, la barra rovesciata e il carattere di nuova riga (che si esegue inserendo una barra rovesciata alla fine di ogni riga eccetto l'ultima ($!s/$/\/ )).

Ciò presuppone che tu usi / come separatore nel tuo sed s comandi e che non abiliti le RE estese con -r (GNU sed /ssed /ast /busybox sed ) o -E (BSD, ast , GNU recente, Busybox recente) o PCRE con -R (ssed ) o RE aumentate con -A /-X (ast ) che hanno tutti operatori RE aggiuntivi.

Alcune regole di base quando si tratta di dati arbitrari:

  • Non utilizzare echo
  • cita le tue variabili
  • considerare l'impatto delle impostazioni locali (in particolare il suo set di caratteri:è importante che l'scappare sed i comandi vengono eseguiti nella stessa locale di sed comando usando il escaped stringhe (e con lo stesso sed comando) per esempio)
  • non dimenticare il carattere di nuova riga (qui potresti voler controllare se $lhs contiene qualsiasi e intraprendere un'azione).

Un'altra opzione è usare perl invece di sed e passa le stringhe nell'ambiente e usa il Q /E perl operatori regexp per prendere le stringhe alla lettera:

A="$lhs" B="$rhs" perl -pe 's/Q$ENV{A}E/$ENV{B}/g'

perl (per impostazione predefinita) non sarà influenzato dal set di caratteri della locale poiché, in quanto sopra, considera le stringhe solo come array di byte senza preoccuparsi di quali caratteri (se presenti) possono rappresentare per l'utente. Con sed , potresti ottenere lo stesso impostando la locale su C con LC_ALL=C per tutti i sed comandi (sebbene ciò influirà anche sulla lingua dei messaggi di errore, se presenti).

Correlati:usare sed con caratteri speciali?
Linux
  1. Come sostituire una stringa in un file?

  2. Come si combinano tutte le righe che terminano con un carattere barra rovesciata?

  3. Come sostituire una stringa con una stringa contenente una barra con Sed?

  4. Sed:eliminare tutte le occorrenze di una stringa tranne la prima?

  5. Come sostituire una stringa in più file nella riga di comando di Linux

Come utilizzare sed per trovare e sostituire la stringa nei file

Come utilizzare Sed per trovare e sostituire una stringa in un file

Come costruire un modulo del kernel Linux in modo che sia compatibile con tutte le versioni del kernel?

Come determini il comando effettivo che ti sta convogliando?

Come rimuovere tutti i file che iniziano con una determinata stringa in Linux

Come catturare tutti i dischi che non hanno un file system