ファイルのパラメータを一致させ、等号文字の後の値のみを置き換えます。

ファイルのパラメータを一致させ、等号文字の後の値のみを置き換えます。

次のサンプルファイルから

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このパラメータはオプションであり、持続する必要がありますが、-iFreeBSDの場合はsed必須です(ただし、空のパラメータを渡すとバック​​アップコピーのアーカイブも無効になります)。

-ire-iGNUとFreeBSDの両方では、これはwith asパラメータとして解釈されます。 FreeBSD では引数を取るものと解釈され、GNU では引数を取らずにオプションが従うと解釈されます。re-i -e-i-e-i-esed

その他の注意事項:

  • -rERE用のGNU -E、。これは POSIX によって指定されます。とにかく、ここではEREは必要ありません。 BREと比較してEREの唯一の特徴は(交互)であり、残りは構文の違いです。うまくいきます。-Esed|sed -i "s/^\(hostname=\).*/\1$escaped_VAR/"
  • .*C入力に(したがってLC_ALL=C)以外のロケールで有効な文字を形成しないバイトシーケンスが含まれている場合、行の最後まで一致しない可能性があります。
  • 渡されたコードの拡張 asis はコンテンツが削除されず、改行文字がエスケープされる場合にコマンド注入の$VAR脆弱性を構成します。上記のように使用すると、シェル変数の内容ではなくリテラルのみが置き換えられます。sed&\/\$VAR$VAR$VAR
  • 値(またはコメントである可能性がある右側の項目)が含まれていない場合は、そうするとその行がs/(hostname=)[^=]*$/$escaped_VAR/置き換えられます。私はこれが意図的なものであることに気づかなかった。hostnamehostname==
  • それ以外の場合は、ファイルのどこにでも^一致します。行の先頭にあるインスタンスのみが完了していることを確認してください。先行スペースを許可するには、常に次のものを使用できます。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

その後、プログラムで使用して、選択した行の先頭以降の値を置き換えることができます。

関連情報