조건에 따라 awk에 빈 줄 추가

조건에 따라 awk에 빈 줄 추가

모두 안녕하십니까,

파일의 일치하는 줄 그룹을 나누기 위해 빈 줄을 사용하고 싶습니다. awk를 처음 접했기 때문에 몇 가지 수정을 거쳐 다음과 같이 생각해 냈습니다.

awk '!($0 in a) {print "\n"; a[$0]}; {print}'

내 마음 속에서 다음과 같이 읽힌다

현재 줄이 배열 "a"에 없으면 개행 문자를 인쇄하고 해당 줄을 "a"에 추가합니다. 현재 줄을 인쇄합니다.

테스트 파일에 대해 실행하면 출력은 다음과 같습니다.



abc
abc


def
def
def


ghi

즉, 하나가 아닌 두 개의 빈 줄이 인쇄됩니다. 추가 라인은 어디서 나오나요?

이것은 내가 사용하는 테스트 파일입니다.

abc
abc
def
def
def
ghi

답변1

연결된 배열이 필요하지 않습니다.

awk 'prev!=""{ print prev!=$0? prev ORS : $0 } { prev=$0 }
END{ if(prev!="") print prev }' infile

산출:

abc
abc

def
def
def

ghi

awk개행 문자를 두 번 인쇄하는 이유 는 print기본적으로 인쇄 중인 내용 + ORS(산소산출오른쪽에코코드에스printf "\n"기본적으로 개행 문자인 구분 기호)를 대신 사용해야 하며 print ""자체 솔루션을 사용하여 다음을 수행할 수 있습니다(몇 가지 수정 사항 적용).

awk '!($0 in a) { if(c++) print "" } { a[$0]; print}' infile

또는 더 간결하게:

awk '!($0 in a) && c++{ print ""} ++a[$0]' infile

답변2

$ awk '{print ($0!=p ? s : "") $0; p=$0; s=ORS}' file
abc
abc

def
def
def

ghi

1줄 대신 2줄의 빈 줄이 인쇄되도록 하는 코드의 버그는 인쇄된 값에 필요한 전부인 print "\n"대신 을 사용하고 있었습니다 .print ""ORS

$ awk 'BEGIN{print "---"; print "\n"; print "---"}'
---


---
$ awk 'BEGIN{print "---"; print ""; print "---"}'
---

---

를 사용할 수도 있지만 이는 단순히 를 사용하는 대신 printf "\n"예상/가정하는 하드코딩된 값을 인쇄합니다 .ORSORSprint ""

내 솔루션과 귀하 솔루션의 주요 기능적 차이점은 귀하의 스크립트는 출력 시작 부분에 빈 줄을 인쇄하지만 내 솔루션은 그렇지 않으며(첫 번째 줄을 인쇄한 후 설정 덕분에 ) s=ORS전체 입력 파일을 저장한다는 것입니다. a[]1개의 입력 라인만 저장하면 이전 입력 라인을 읽습니다 p.

  1. 귀하의 스크립트는 많은 메모리를 사용하므로 대용량 입력 파일에서는 실패할 수 있지만 제 스크립트는 모든 크기의 입력 파일에서 작동합니다.
  2. 이전에 입력의 어느 곳에도 입력 행이 나타나지 않은 경우 스크립트는 빈 행을 인쇄하는 반면, 내 스크립트는 입력이 변경될 때마다 빈 행을 인쇄하므로 입력 행이 항상 그룹화되지 않으면 동작이 각각 다릅니다. 기타 예:
    $ printf 'foo\nbar\nfoo\n'
    foo
    bar
    foo

    $ printf 'foo\nbar\nfoo\n' | awk '!($0 in a) {print ""; a[$0]}; {print}'
    
    foo
    
    bar
    foo

    $ printf 'foo\nbar\nfoo\n' | awk '{print ($0!=p ? s : "") $0; p=$0; s=ORS}'
    foo
    
    bar
    
    foo

코드에서 수행하려는 작업을 수행하기 위해 명명된 배열을 사용하는 대신 배열을 개별적으로 업데이트하는 대신 a[]관용적으로 배열 이름을 지정 seen[]하고 테스트하는 동안 업데이트하므로 코드는 다음 awk '!seen[$0]++{print ""} 1'과 같이 관용적으로 작성됩니다 awk '!($0 in a) {print ""; a[$0]}; {print}'.

$ printf 'foo\nbar\nfoo\n' | awk '!seen[$0]++{print ""} 1'

foo

bar
foo

공백 행 없이 함수를 출력하려면 다음을 선택하십시오.

$ printf 'foo\nbar\nfoo\n' | awk '{print (seen[$0]++ ? "" : s) $0; s=ORS}'
foo

bar
foo

$ printf 'foo\nbar\nfoo\n' | awk '!seen[$0]++ && NR>1{print ""} 1'
foo

bar
foo

$ printf 'foo\nbar\nfoo\n' | awk '!seen[$0]++{if (NR>1) print ""} 1'
foo

bar
foo

$ printf 'foo\nbar\nfoo\n' | awk '!seen[$0]++{printf s; s=ORS} 1'
foo

bar
foo

ORS에 printf 형식 문자가 포함된 경우 마지막 항목은 실패합니다. 예를 들면 다음과 같습니다.

$ printf 'foo\nbar\nfoo\n' | awk -v ORS='\n%s\n' '!seen[$0]++{printf s; s=ORS} 1'
foo
%s
awk: cmd. line:1: (FILENAME=- FNR=2) fatal: not enough arguments to satisfy format string
        `
%s
'
          ^ ran out for this one

따라서 이것이 문제인 경우 다음과 같이 더 강력하게 작성할 수 있습니다.

$ printf 'foo\nbar\nfoo\n' | awk -v ORS='\n%s\n' '!seen[$0]++{printf "%s", s; s=ORS} 1'
foo
%s

%s
bar
%s
foo
%s

관련 정보