Aby uniknąć zmiennych, które będą używane po lewej i prawej stronie spolecenia w sed( odpowiednio $lhsi tutaj $rhs), należy:
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/"
Uwaga: $lhsnie może zawierać znaku nowej linii.
Oznacza to, że w LHS unikaj wszystkich operatorów wyrażeń regularnych ( ][.^$*), samego znaku ucieczki ( \) i separatora ( /).
W RHS wystarczy tylko uciec &, separator, odwrotny ukośnik i znak nowej linii (co robisz, wstawiając odwrotny ukośnik na końcu każdego wiersza z wyjątkiem ostatniego ( $!s/$/\\/)).
Zakłada się, że używasz /jako separatora w swoich sed spoleceniach i że nie włączasz rozszerzonych RE z -r(GNU sed/ ssed/ ast/ busybox sed) lub -E(BSD ast, ostatnio GNU, ostatnio zajęty ) lub PCRE z -R( ssed) lub rozszerzonych RE z -A/ -X( ast), które wszyscy mają dodatkowych operatorów RE.
Kilka podstawowych zasad dotyczących arbitralnych danych:
- Nie używaj
echo
- podaj swoje zmienne
- rozważ wpływ ustawienia narodowego (zwłaszcza jego zestawu znaków: ważne jest, aby polecenia ucieczkowe
sed były uruchamiane w tym samym języku, co sedpolecenie, na przykład za pomocą znaków ucieczki (i tej samej sedkomendy))
- nie zapomnij o znaku nowej linii (tutaj możesz sprawdzić, czy
$lhszawiera jakiś znak i podjąć działania).
Inną opcją jest użycie perlzamiast sedi przekazanie ciągów w środowisku oraz użycie operatorów \Q/ \E perlregexp do dosłownego pobierania ciągów:
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl(domyślnie) zestaw znaków ustawień regionalnych nie będzie miał na to wpływu, ponieważ powyżej traktuje ciągi jako tablice bajtów bez dbania o to, jakie znaki (jeśli występują) mogą reprezentować dla użytkownika. Dzięki sed, można osiągnąć to samo poprzez ustalenie locale aby Cze LC_ALL=Cwszystkich sedkomend (mimo że wpłynie także na język komunikatów o błędach, jeśli w ogóle).