Per sfuggire alle variabili da usare sul lato sinistro e sul lato destro di un s
comando sed
(qui $lhs
e $rhs
rispettivamente), dovresti fare:
escaped_lhs=$(printf '%s\n' "$lhs" | sed 's:[][\/.^$*]:\\&:g')
escaped_rhs=$(printf '%s\n' "$rhs" | sed 's:[\/&]:\\&:g;$!s/$/\\/')
sed "s/$escaped_lhs/$escaped_rhs/"
Si noti che $lhs
non può contenere un carattere di nuova riga.
Cioè, su LHS, sfuggire a tutti gli operatori regexp ( ][.^$*
), al carattere di escape stesso ( \
) e al separatore ( /
).
Sull'RHS, devi solo scappare &
, il separatore, la barra rovesciata e il carattere di nuova riga (cosa che fai inserendo una barra rovesciata alla fine di ogni riga tranne l'ultima ( $!s/$/\\/
)).
Ciò presuppone che tu usi /
come separatore nei tuoi sed
s
comandi e che non abiliti le RE estese con -r
(GNU sed
/ ssed
/ ast
/ busybox sed
) o -E
(BSD, ast
GNU recente, recente scatola occupata ) o PCRE con -R
( ssed
) o le RE aumentate con -A
/ -X
( ast
) che tutti hanno operatori RE extra.
Alcune regole di base quando si tratta di dati arbitrari:
- Non usare
echo
- cita le tue variabili
- considerare l'impatto della locale (in particolare il suo set di caratteri: è importante che i comandi di escape
sed
siano eseguiti nella stessa locale del sed
comando usando ad esempio le stringhe di escape (e con lo stesso sed
comando))
- non dimenticare il carattere di nuova riga (qui potresti voler controllare se ne
$lhs
contiene qualcuno e agire).
Un'altra opzione è quella di utilizzare perl
invece sed
e passare le stringhe nell'ambiente e utilizzare gli operatori \Q
/ \E
perl
regexp per prendere letteralmente le stringhe:
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 solo le stringhe come matrici di byte senza preoccuparsi di quali caratteri (se presenti) possono rappresentare per l'utente. Con sed
, è possibile ottenere lo stesso risultato fissando la locale su C
con LC_ALL=C
per tutti i sed
comandi (anche se ciò influirà anche sulla lingua dei messaggi di errore, se presenti).