Mám skript, který čte textový proud a generuje soubor příkazů sed, který se později spustí pomocí sed -f
. Vygenerované příkazy sed jsou podobné:
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
Předpokládejme skript, který generuje sed
příkazy je něco jako:
while read cid fileid
do
cidpat="$(echo $cid | sed -e s/\./\\./g)"
echo 's/'"$cidpat"'/https://mysite.com/files/'"$fileid"'/g' >> sedscr
done
Jak mohu zlepšit skript, abych zajistil všechny metaznaky regulárního výrazu v cid
jsou escapovány a správně interpolovány?
Přijatá odpověď:
Chcete-li uniknout proměnným, které mají být použity na levé a pravé straně s
příkaz v sed
(zde $lhs
a $rhs
respektive), udělali byste:
escaped_lhs=$(printf '%sn' "$lhs" | sed 's:[][\/.^$*]:\&:g')
escaped_rhs=$(printf '%sn' "$rhs" | sed 's:[\/&]:\&:g;$!s/$/\/')
sed "s/$escaped_lhs/$escaped_rhs/"
Všimněte si, že $lhs
nemůže obsahovat znak nového řádku.
To znamená, že na LHS unikněte všem operátorům regulárních výrazů (][.^$*
), samotný únikový znak ( ) a oddělovač (
/
).
Na RHS stačí uniknout &
, oddělovač, zpětné lomítko a znak nového řádku (což provedete vložením zpětného lomítka na konec každého řádku kromě posledního ($!s/$/\/
)).
To předpokládá, že používáte /
jako oddělovač ve vašem sed
s
a že nepovolíte Extended REs s -r
(GNU sed
/ssed
/ast
/busybox sed
) nebo -E
(BSD, ast
, nedávný GNU, nedávný busybox) nebo PCRE s -R
(ssed
) nebo Augmented REs s -A
/-X
(ast
), které mají všechny další operátory RE.
Několik základních pravidel pro práci s libovolnými daty:
- Nepoužívejte
echo
- uveďte své proměnné
- vezměte v úvahu dopad národního prostředí (zejména jeho znakové sady:je důležité, aby escapování
sed
příkazy se spouštějí ve stejném národním prostředí jakosed
pomocí příkazu escaped řetězců (a se stejnýmsed
například příkaz) - nezapomeňte na znak nového řádku (zde možná budete chtít zkontrolovat, zda
$lhs
obsahuje jakékoli a proveďte akci).
Další možností je použít perl
místo sed
a předejte řetězce v prostředí a použijte Q
/E
perl
Operátory regulárních výrazů pro doslovné přebírání řetězců:
A="$lhs" B="$rhs" perl -pe 's/Q$ENV{A}E/$ENV{B}/g'
perl
(ve výchozím nastavení) nebude ovlivněna znakovou sadou národního prostředí, protože ve výše uvedeném považuje řetězce pouze za pole bajtů, aniž by se starala o to, jaké znaky (pokud existují) mohou pro uživatele představovat. Pomocí sed
, můžete toho dosáhnout tím, že upravíte národní prostředí na C
s LC_ALL=C
pro všechny sed
příkazy (i když to také ovlivní jazyk chybových zpráv, pokud existují).