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í
sedpříkazy se spouštějí ve stejném národním prostředí jakosedpomocí příkazu escaped řetězců (a se stejnýmsednapříklad příkaz) - nezapomeňte na znak nového řádku (zde možná budete chtít zkontrolovat, zda
$lhsobsahuje 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í).