패턴의 첫 번째 발생(만) 사이에서 수정(포함) 및 계속 처리

패턴의 첫 번째 발생(만) 사이에서 수정(포함) 및 계속 처리

두 패턴의 첫 번째 발생 간의 일치와 관련하여 몇 가지 문제가 있습니다(예:이것) - 그러나 그들은 모두 그것에 의존하는 것 같습니다 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있습니다.

*"한 줄"은 상당히 복잡한 줄일 수 있지만 여전히 이해하기 쉽고 합리적인 종료 코드를 생성하기를 원합니다. 이를 AWS CloudFormation 템플릿에 넣으려고 합니다.

FWIW

$awk -V
GNU Awk 4.0.2

감사해요!

답변1

awk스크립트의 "패턴"(즉, 패턴 이전) {내에서 가능한 한 많은 테스트를 수행 해야 한다는 철학이 있는 것 같습니다  . 나는 이 문제를 접하기 오래 전부터 C와 다른 언어로 프로그래밍을 해왔기 때문에 awk필요할 때 한두 개의 문장(또는 세 개)을 사용하는 것을 꺼리지 않습니다.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향후 모든 일치 항목이 주석 처리되도록 플래그를 설정합니다.
  • 우리가 댓글을 달면
    • 해당 줄에 주석이 달린 경우 그대로 인쇄합니다.
    • 그렇지 않으면 #앞에 하나를 추가하십시오.

주석 처리되지 않은 코드는 첫 번째 블록에 다음이 없다고 가정합니다.포함하다어떤 충고. 예를 들어,

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

로 변경됩니다

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

이것은 버그인 것 같습니다.

관련 정보