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