次のサンプルファイルから
more ambari-agent.ini
[server]
hostname=AABB
ファイルの単語を一致させ、hostname
その後の値(同じ文字)のみを変更しようとします。=
だから私たちはやった
VAR=server_100
sed -ire "s/(hostname=)[^=]*$/\$VAR/" /tmp/ambari-agent.ini
しかし、私たちはまだ
more ambari-agent.ini
[server]
hostname=AABB
予想される結果は次のとおりです。
more ambari-agent.ini
[server]
hostname=server_100
私たちはどこで間違っていますか?
答え1
VAR=anything
escaped_VAR=$(
printf '%s\n' "$VAR" |
LC_ALL=C sed 's|[/&\\]|\\&|g;$!s/$/\\/'
)
LC_ALL=C sed -E -i -e "s/^(hostname=).*/\1$escaped_VAR/" -- "$the_file"
FreeBSD / macOSの場合にsed
置き換えてください。-i
-i ''
GNU(最終的にFreeBSDの代わりにGNUをコピーしたNetBSD / OpenBSD)とFreeBSDの場合は、バックアップsed
拡張-i
名という1つの引数を使用します。 GNUの場合、sed
このパラメータはオプションであり、持続する必要がありますが、-i
FreeBSDの場合はsed
必須です(ただし、空のパラメータを渡すとバックアップコピーのアーカイブも無効になります)。
-ire
-i
GNUとFreeBSDの両方では、これはwith asパラメータとして解釈されます。 FreeBSD では引数を取るものと解釈され、GNU では引数を取らずにオプションが従うと解釈されます。re
-i -e
-i
-e
-i
-e
sed
その他の注意事項:
-r
ERE用のGNU-E
、。これは POSIX によって指定されます。とにかく、ここではEREは必要ありません。 BREと比較してEREの唯一の特徴は(交互)であり、残りは構文の違いです。うまくいきます。-E
sed
|
sed -i "s/^\(hostname=\).*/\1$escaped_VAR/"
.*
C
入力に(したがってLC_ALL=C
)以外のロケールで有効な文字を形成しないバイトシーケンスが含まれている場合、行の最後まで一致しない可能性があります。- 渡されたコードの拡張 asis はコンテンツが削除されず、改行文字がエスケープされる場合にコマンド注入の
$VAR
脆弱性を構成します。上記のように使用すると、シェル変数の内容ではなくリテラルのみが置き換えられます。sed
&
\
/
\$VAR
$VAR
$VAR
- 値(またはコメントである可能性がある右側の項目)が含まれていない場合は、そうするとその行が
s/(hostname=)[^=]*$/$escaped_VAR/
置き換えられます。私はこれが意図的なものであることに気づかなかった。hostname
hostname=
=
- それ以外の場合は、ファイルのどこにでも
^
一致します。行の先頭にあるインスタンスのみが完了していることを確認してください。先行スペースを許可するには、常に次のものを使用できます。hostname=
^
hostname=
"/^([[:space:]]*hostname...
1 POSIX EREはBREの逆参照機能も欠けていますが、現在ほとんどのERE実装はそれを拡張としてサポートしています。
答え2
以前の回答も機能として機能するので、そこにコメントに答えるには評判が不足しています。
VAR=anything
function escape() { printf '%s\n' "$1" | LC_ALL=C sed 's|[+/&\\]|\\&|g;$!s/$/\\/' }
LC_ALL=C sed -E -e "s/^(hostname=).*/\1$(escape $VAR)/" -i -- "$file"
+
ルールをエスケープするように文字を変更しました。
VAR
これは、動的にまたは他の方法で提供される代替値にも当てはまります。
LC_ALL=C sed -E -e "s/^(> API_SECRET=).*/\1$(escape $(pwgen -n 64 1))/" -i -- diff.patch
VAR="admin"; LC_ALL=C sed -E -e "s/^(+SP_ADMIN_USER=).*/\1$(escape "${VAR}")/" -i diff.patch
-e
このコマンドは潜在的に重複する可能性があるため、元の例とは異なり、省略されています--
。
このロジックは、完全に省略された他の関数を使用してさらにパラメータ化できますVAR
。
function replace() { LC_ALL=C sed -E -e "s/^($(escape "${1}")).*/\1$(escape "${2}")/" -i "${3}" }
replace "+ADMIN_USER=" "admin" diff.patch
その後、プログラムで使用して、選択した行の先頭以降の値を置き換えることができます。