awk -- 같은 줄의 직접 패턴 이후에 한 번 교체하세요!

awk -- 같은 줄의 직접 패턴 이후에 한 번 교체하세요!

1.5MB 파일이 있습니다.
한 줄에는 약 160,000개의 문자가 있습니다.
이 줄에서는 PATTERN 직후에 "false"를 "true"로 한 번만 변경하면 됩니다.

awk 이후에는 첫 번째 발생만 변경됩니다.
하지만 "PATTERN" 이후에는 한 번만 변경하면 됩니다.

awk '/PATTERN.*false/ {sub("false", "true")} {print}' file

우리의 파일은 다음과 같습니다:

...
colorA is false colorB is false PATTERN is false colorC is false colorD is false
...

파일에는 다음이 있어야 합니다.

...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...

필요에 맞게 awk 명령을 어떻게 배열합니까?

미리 감사드립니다!

답변1

"false"와 일치하지 않는 가장 짧은 문자열과 일치하는 정규식을 작성하는 것은 이론적으로 가능하지만 어렵습니다. 다른 다양한 언어에는 select-shortest 구문이 있지만 awk는 그중 하나가 아닙니다.

따라서 어려운 표현을 작성하고 싶지 않다고 가정하면 3가지 접근 방식이 있습니다.

  1. 입력을 "false"라는 단어로 분할하고 필드를 반복하여 현재 필드가 패턴과 일치하면 "true" 뒤에 인쇄하고, 그렇지 않으면 "false" 뒤에 인쇄할 수 있습니다.
  2. 트릭을 사용하여 "false"의 모든 항목을 control-a와 같은 사용하지 않는 단일 문자로 변환할 수 있습니다. 그러면 정규식은 가장 짧은 모드 제어로 끝나는 것과 일치하도록 [^\001]*\001이라고 말할 수 있는 것처럼 작성하기 쉽습니다. -ㅏ.
  3. 필드를 반복하고 현재 필드가 스키마인 경우 플래그를 설정하고, "false"이고 플래그가 설정된 경우 "true"로 변경하고 플래그를 재설정합니다.

방법 3의 경우.

#!/usr/bin/awk

/PATTERN.*false/ {
        for(i=1;i<=NF;i++) {
                if ($i ~ /PATTERN/) flag=1;
                if ($i == "false" && flag==1) {
                        $i="true"
                        flag=0
                }
        }
}
{print}

그러면 입력의 공백이 축소됩니다.

답변2

PATTERN솔루션은 ( )에서 라인 분할을 구현하고 split, 첫 번째 부분을 false두 번째 부분( )으로 대체하고 해당 부분을 결합합니다( 루프 합계 ). 이 명령은 이 입력 라인의 추가 처리를 건너뜁니다. 다른 줄은 변경되지 않고 인쇄됩니다. ( 기본 동작이 있는 경우 항상 참인 조건입니다.)subforprintfnext1

awk '/PATTERN.*false/ {
    n=split($0,parts,"PATTERN"); 
    sub("false", "true", parts[2]); 
    for(i=1;i<n;i++) {
        printf("%s%s", parts[i], "PATTERN");
    }
    printf("%s\n", parts[n]);
    next }
1'

PATTERN해당 값이 항상 존재 하는지 여부가 질문에서 명확하지 않으므로 false대체 오류일 수 있습니다 false.

입력 샘플

colorA is false colorB is false PATTERN is false colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is false colorD is false

결과는 다음과 같습니다.

colorA is false colorB is false PATTERN is true colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is true colorD is false

편집하다~에 따르면루딕참고: PATTERN 이후 수정될 값이 "true" 또는 "false"인 경우 지시문을 다음과 같이 바꾸면 이 sub("false", "true", parts[2]);문제를 피할 수 있습니다.sub("false|true", "true", parts[2]);

awk '/PATTERN.*false/ {
    n=split($0,parts,"PATTERN"); 
    sub("false|true", "true", parts[2]); 
    for(i=1;i<n;i++) {
        printf("%s%s", parts[i], "PATTERN");
    }
    printf("%s\n", parts[n]);
    next }
1'

동일한 샘플 입력을 사용하면 결과는 다음과 같습니다.

colorA is false colorB is false PATTERN is true colorC is false colorD is false
colorA is false colorB is false PATTERN is true colorC is false colorD is false

답변3

GNU awk를 사용하여 match() 및 gensub()에 세 번째 인수를 전달합니다.

$ awk 'match($0,/(.*PATTERN)(.*)/,a){$0=a[1] gensub(/false/,"true",1,a[2])} 1' file
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...

그리고 어떤 이상한 :

$ awk 'match($0,/.*PATTERN/){tail=substr($0,RSTART+RLENGTH); sub(/false/,"true",tail); $0=substr($0,1,RSTART+RLENGTH-1) tail } 1' file
...
colorA is false colorB is false PATTERN is true colorC is false colorD is false
...

관련 정보