パターンの最初の発生(のみ)間で修正(含む)と継続処理

パターンの最初の発生(のみ)間で修正(含む)と継続処理

2つのパターンの最初の発生間の一致にはいくつかの問題があります。これ) - しかし、彼らはすべてそれに依存しているようですexit。ファイルの操作を続けたいので、これは良くありません。

私がやろうとしているのは、パターン間の最初の範囲(他の項目ではない)を修正して別のawk fooを実行することです。特にdovecot confファイルの特定の部分に注釈を付けようとします。本当に理想的な世界では、このuserdb { driver = prefetch }ブロックのコメントを解除し、他のすべてのブロックのコメントを保証するために*行を追加したいと思いますuserdb { }。しかし、ファイルは少なくとも予測可能なので、私の目標は、最初のコメントブロックのコメント処理を削除してから、他のすべてのブロックにコメントを付けることです。

私は持っています

... some stuff that should be echoed as is ...
#userdb {
#  driver = prefetch
#}
... more stuff
userdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
... still more stuff
#userdb {
  #driver = static
  #args = uid=vmail gid=vmail home=/var/vmail/%u
#}

そして私は欲しい

... original stuff ...
userdb {
  driver = prefetch
}
... more stuff
#userdb {
#  driver = sql
#  args = /etc/dovecot/dovecot-sql.conf.ext
#}
... still more stuff
#userdb {
  #driver = static
  #args = uid=vmail gid=vmail home=/var/vmail/%u
#}

私は何らかの目的でawkにフラグを設定すると思いました。

awk '/^#userdb/,/^#}/ && !ididit {
        print substr($0,2);
        next;
        ididit=1;
    }
    /^userdb/,/}/ {
        print "#", $0;
        next
    }
    {print}' auth-sql.conf.ext

これはほぼ似ていますが、ididitフラグを設定しても(実際に設定されていることを確認するために複数の印刷物を追加しました)、切り捨てられませんでした。

... original stuff ...
userdb {
  driver = prefetch
}
... more stuff
# userdb {
#   driver = sql
#   args = /etc/dovecot/dovecot-sql.conf.ext
# }
... more stuff ...
userdb {
 #driver = static
 #args = uid=vmail gid=vmail home=/var/vmail/%u
}

最後userdb {}のブロックはそれ自体でコメントを解除します。これを知るまではとても迷惑でした。内蔵の奥深くGNU awk文書のこの小さな宝石は次のとおりです。

echo Yes | awk '/1/,/2/ || /Yes/'

このアプリの作成者はこれを意図していません(/1/,/2/) || /Yes/。しかし、awkはこれをと解釈します /1/, (/2/ || /Yes/)。これは変更または解決できません。範囲パターンは他のパターンと結合されない。

だから私の子供は&& !ididit役に立たない人です。

これらすべてを一行で(または上記の「本当に理想的な世界で」)実現する方法についての提案はありますか?perlオプションではありませんが、これも可能sedですbash

*「1行」はかなり複雑な縮小かもしれませんが、それでも理解しやすく合理的な終了コードを生成したいと思います。これをAWS CloudFormationテンプレートに配置しようとしています。

FWIW

$awk -V
GNU Awk 4.0.2

ありがとうございます!

答え1

awkスクリプトの「パターン」(つまり、パターンの前){内でできるだけ多くのテストを実行する必要があるという哲学があるようです。私はこの問題に遭遇するずっと前からCとは異なる言語でプログラミングしてきたので、awk必要に応じて1つまたは2つの文章(または3つ)を使用することを気にしません。if

だからこれが私が思いついたものです:

awk '/userdb/,/}/ {
        if (!comment) {                         # Uncomment the first one
                sub("#", "")
                print
                if ($0 ~ /}/) comment=1         # All others get commented
        } else {
                if ($0 ~ /^[[:blank:]]*#/) {    # Already commented out?
                        print
                } else {
                        print "#" $0
                }
        }
        next
      }
      { print }
    '

これは明らかにあなたのコードに基づいています。  commentはあなたに似た変数ですididit。最初は0(false)で、最初のブロックが処理された後に1(true)に設定されます。

-block/userdb/内で/}/

  • コメントをキャンセルすると
    • 存在する場合はsub削除に使用されます。#これは無条件に最初の文字を切り取るよりも安全です。すでにコメントしていませんか?
    • }ブロックの終わりを表示すると、将来のcommentすべての一致がコメントアウトされるようにフラグを設定します。
  • 私たちがコメントしたら
    • その行にコメントがある場合は、そのまま印刷します。
    • それ以外の場合は、#前に1つを追加してください。

コメントアウトされていないコードは、最初のブロックに次のものがないと仮定します。含むどんなアドバイス。例えば、

userdb {
  driver = prefetch     # We want to keep this uncommented.
}

に変更されます

userdb {
  driver = prefetch      We want to keep this uncommented.
}

これはバグのようです。

関連情報