복잡한 정규식 sed 교체가 작동하지 않지만 오류가 발생하지 않습니다.

복잡한 정규식 sed 교체가 작동하지 않지만 오류가 발생하지 않습니다.

저는 CentOS 7에서 작업 중이며 find/sed oneliner를 사용하여 많은 수의 파일을 복구하려고 합니다. 구체적으로 말하면, 연속으로 두 개가 있습니다.

  1. [monitor://...]먼저 각 (작업) 바로 뒤에 "ignoreOlderThan = 14d"를 추가합니다.
  2. 둘째, [monitor://...]두 개의 "ignoreOlderThan"이 있는 그룹을 찾아 마지막 항목을 삭제합니다.

다음과 유사한 파일이 수백 개 있습니다(이것이 제가 사용하고 있는 현재 테스트 파일입니다).

[default]
host = 10.2.2.15

[monitor://apath]
ignoreOlderThan = 14d
index=test
sourcetype=whatever
ignoreOlderThan = 30d

[monitor://truck]
ignoreOlderThan = 14d

[monitor://apath]
ignoreOlderThan = 14d
index=test
sourcetype=whatever
ignoreOlderThan = 30d

내가 사용한 첫 번째 완전한 명령은 다음과 같습니다.

find -name inputs.conf -exec sed -ie 's/\(\[monitor:.*\]\)/\1\nignoreOlderThan = 14d/g' {} +

이것은 작동합니다. ignoreOlderThan = 14d바로 뒤에 추가 되었습니다 [monitor://...].

두 번째는 더 복잡하고 작동하지 않습니다.

find -name inputs.conf -exec sed -ie 's/\(\[monitor[^\]]+\][^\[]?\)\(ignoreOlderThan\s?=\s?[0-9]+\w\)\([^\[]+?ignoreOlderThan\s?=\s?[0-9]+\w\)\([^\[]+\)?/\1\3\4/g' {} +

regex101을 사용하여 몇 가지 가능한 시나리오를 테스트했습니다.

https://regex101.com/r/okCSfl/6

https://regex101.com/r/okCSfl/7

https://regex101.com/r/okCSfl/8

https://regex101.com/r/okCSfl/9

정규식은 작동하므로 문제는 sed 명령 어딘가에 있고 능력이 훨씬 떨어지는 것 같습니다. 캡처 그룹에 필요에 따라 대괄호를 이스케이프 처리했으며 명령이 실행되지만 아무 작업도 수행되지 않습니다. 가끔 네 번째 캡처 그룹이 없기 때문일 수도 있다고 생각했지만 각 그룹에 4개의 캡처 그룹이 모두 포함된 파일도 테스트했습니다.

나는 또한 일부 sed가 모든 것을 한 줄로 해석한다는 것을 읽었습니다. 이것이 바로 내 테스트 케이스 중 일부가 개행 사이에 공백이 전혀 없는 이유입니다.


편집: @choroba는 sed가 한 번에 한 줄씩 실행된다는 점을 지적하고 perl을 제안하고 예제를 제공했습니다. 나는 그것을 가지고 놀았고 다음과 같이 작동하게 만들었습니다.

find -name inputs.conf -exec perl -0777 -pi -e 's/(\[monitor:[^[]+?)^(ignoreOlderThan\s?=\s?[0-9]+\w)([^[]+?^ignoreOlderThan\s?=\s?[0-9]+\w[^[]+)/$1$3/gms' {} +

여기 데모:

https://regex101.com/r/okCSfl/10

답변1

sed는 입력을 한 줄씩 처리합니다. 정규식은 여러 줄을 쉽게 일치시킬 수 없습니다.

반면 Perl은 -0777옵션이 지정되면 전체 파일을 읽을 수 있습니다.

perl -0777 -pe 's/^(\[monitor:[^[]+^ignoreOlderThan .*)^ignoreOlderThan = \w+/$1/gms' input > output
  • -0777전체 파일을 먹어라
  • -p처리 후 인쇄 입력
  • /g교체를 반복
  • /s개행 문자 일치 .(보통 그렇지 않음)
  • /m^전체 문자열뿐만 아니라 각 개행의 시작 부분에서 일치합니다(비슷 $하지만 여기서는 필요하지 않음).

관련 정보