ありがとうこのリンク私はどうするか知っていますスラッシュを含む変数を渡すsedパターンで:
sed "s~$var~replace~g" $file
。 / 代わりにシングルバイト文字を使用してください。
ありがとうこの他のリンク私も知る方法ファイルに最初に表示されるパターンのみを置き換える(同じ行にはありません):
sed "0,/$var/s/$var/replacement/" filename
または
sed 0,/$var/{s/$var/replacement/} filename
しかし、それを行うと(
sed '0,~$var~s~$var~replacement~' filename
またはゼロで始まり、スラッシュがない他のもの)エラーが発生します。unknown command: '0'
この2つをどのように組み合わせることができますか?おそらくawkやPerlを使うか…?
答え1
しかし:
sed "0,\~$var~s~$var~replacement~"
正規表現の区切り文字を変更するために使用できます。sed
通常、コード(または他のインタプリタ)コードに変数拡張を含めることは非常に賢明ではありません。
まず、この区切り文字はエスケープする必要がある唯一の文字ではありません。これはすべての正規表現演算子にも必要です。
しかし、より重要なことは、特にGNUの場合、sed
これはコマンドインジェクションの脆弱性です。コンテンツを$var
制御できない場合は、任意のデータをeval
。
たとえば、次のようになります。
$ var='^~s/.*/uname/e;#'
$ echo | sed "0,\~$var~s~$var~replacement~"
Linux
コマンドuname
が実行され、幸い今回は無害でした。
GNU以外sed
の実装では任意のコマンドを実行することはできませんが、コマンドを使用してすべてのファイルを上書きすることができます。w
これは実際には同じです。
より正確な方法は$var
まず、問題のある文字を脱出してください:
NL='
'
case $var in
(*"$NL"*)
echo >&2 "Sorry, can't handle variables with newline characters"
exit 1
esac
escaped_var=$(printf '%s\n' "$var" | sed 's:[][\/.^$*]:\\&:g')
# and then:
sed "0,/$escaped_var/s/$escaped_var/replacement/" < file
別の方法は、次のものを使用することですperl
。
var=$var perl -pe 's/\Q$ENV{var}\E/replacement/g && $n++ unless $n' < file
$var
渡されたコード内の内容を拡張せずにperl
(別のコマンドインジェクションの脆弱性になる可能性があります)、代わりにperl
その内容を正規表現処理の一部に拡張します(\Q...\E
つまり、正規表現演算子が特に処理されないことを意味します)。
改行文字が含まれている場合は、$var
最後に 1 つだけで一致が可能です。あるいは、-0777
入力が1行ずつ処理されず、単一のレコードとして処理されるようにこのオプションを渡すこともできます。
答え2
Stephaneのソリューションと同様に、perl
「awk
危険な」補間を保護する問題は、代替手段によって回避できます。
export pattern="anypattern" # or whatever shell quoting is needed
awk 'NR==1,$0~ENVIRON["pattern"] {sub(ENVIRON["pattern"],"replacement")} 1' input
# or gsub if you want multiple matches on the first line with any match
データが(おそらく)大きく、パターンが(おそらく)高価な場合は、わずかにawk
異なるイディオムと一致するものを見つけると、不要な一致を避けることができます。
awk '!x&&$0~ENVIRON["pattern"] {sub(ENVIRON["pattern"],"replacement");x=1} 1' input
# ditto
注意:(awk
またはsed
)実際のプレフィックスが&
必要な場合(通常は最初にシェルから引用する必要があり、ここではにある)、同様に実際のプレフィックスを2倍にします。&
\
''
\