一致する2行の後に一致するテキストを置き換える

一致する2行の後に一致するテキストを置き換える

次のセクションを含むYAMLファイルがあります。

admin::common::passwords:
  alice:
    password: '$6$oTQhLvN/4VFJPscD$8LYwUMSFi'
  bob:
    password: '$6$JKOtLF0wHeZfIskt$W/M5.ugDS'

シェル変数$ ACCOUNTにアカウント名(alice、bobなど)が含まれていて、$ YAMLがYAMLファイルのファイル名である場合は、次のようにsedを使用して新しいエントリを追加できます。 "admin::common::passwords:" 行の直下に新しいアカウントが挿入されるので、そのアカウントが正しいセクションにあることがわかります。

  sed -i /'^admin::common::passwords:'/a"\  ${ACCOUNT}:\n    password: '${ENCRYPTED_PASS}'" $YAML

awkを使用して、このような既存のアカウントを見つけることができます。今回もセクションを見つけて、そのセクション内のアカウントを見つけます(awkでこれを行うことは可能かもしれませんが、awkでは十分ではないのでこれを行います)。

  awk "BEGIN{RS=ORS="\n\n";FS=OFS="\n"}/admin::common::passwords:/" $YAML | grep -A1 "^[ ]*${ACCOUNT}:"

しかし、行を削除するには、私が考えることができる最善の方法は次のとおりです。

sed -i "/^  ${ACCOUNT}:/,+1d" $YAML

これにより、admin::common::passwords セクションか他の場所にあっても、ファイル内のすべての "^alice:" 行が削除されます。

ファイルに admin::common:passwords セクションが含まれていること以外は、ファイルの内容について何の前提もできません(そうでなければ、私のスクリプトの他の部分によって生成されます。そのビットは単純です)。

だから私の質問は:sedの面でこれをどのように改善できますか?"^${ACCOUNT}:" 検索admin::common::passwords セクションでをタップして、一致する行とその下の行を削除します。'?

(もちろん、sedを使用する必要はありません。awkまたはPerlが作業に適している可能性もあります。)

ベストアンサー1

sed "
  /^admin::common::passwords:$/,/^[^ ].*:$/ {
     /^  $ACCOUNT:$/ {
       N;d
     }
  }" < "$YAML"

つまり、削除されたセクションをadmin::common...次のセクションと一致するセクションに含めますwhatever-section:

ユーザー名によく使われる文字.も正規表現演算子なので、とjohn.doe一致john.doeするjohnWdoeが、例えば。

admin::common::passwords2つの連続したセクションがあり、削除するアカウントが2番目のセクションにある場合、上記の方法は機能しません。

もし、オシウスが指摘したように、セクションは、同じまたはより少ない先行スペース文字を使用して次の行で実行され、セクションにadmin::common::passwords:先行スペースがある可能性があります。これにより、他の言語に切り替える必要がある場合がありますawk。たとえば、次のようになります。

awk -v account="$ACCOUNT" '
  match($0, /[^ ]/) && RSTART <= n {n = 0}
  n && NF == 1 && $1 == account ":" {getline; next}
  !n && /^ *admin::common::passwords:$/ {
    match($0, /[^ ]/)
    n = RSTART
  }
  {print}' < "$YAML"

おすすめ記事