각 파일의 처음 몇 줄을 생략하면서 세 파일의 "그룹 병합"을 어떻게 수행할 수 있습니까?

각 파일의 처음 몇 줄을 생략하면서 세 파일의 "그룹 병합"을 어떻게 수행할 수 있습니까?

재현 가능한 예는 다음과 같습니다.

  • file01.txt

    line to skip
    line to skip
    line to skip
    line to keep file 01
    heading 1 in the form: 2017243 01 2017243 01
    data 1 file 01
    heading 2 in the form: 2017243 02 2017243 02
    data 2 file 01
    heading 3 in the form: 2017243 03 2017243 03
    data 3 file 01
    
  • file02.txt

    line to skip
    line to skip
    line to skip
    line to keep file 02
    heading 1 in the form: 2017243 01 2017243 01
    data 1 file 02
    heading 2 in the form: 2017243 02 2017243 02
    data 2 file 02
    heading 3 in the form: 2017243 03 2017243 03
    data 3 file 02
    
  • file03.txt

    line to skip
    line to skip
    line to skip
    line to keep file 03
    heading 1 in the form: 2017243 01 2017243 01
    data 1 file 03
    heading 2 in the form: 2017243 02 2017243 02
    data 2 file 03
    heading 3 in the form: 2017243 03 2017243 03
    data 3 file 03
    
  • 원하는 출력

    line to keep file 01
    line to keep file 02
    line to keep file 03
    heading 1 in the form: 2017243 01 2017243 01
    data 1 file 01
    data 1 file 02
    data 1 file 03
    heading 2 in the form: 2017243 02 2017243 02
    data 2 file 01
    data 2 file 02
    data 2 file 03
    heading 3 in the form: 2017243 03 2017243 03
    data 3 file 01
    data 3 file 02
    data 3 file 03
    

지금까지 나는 다음을 통해 각 입력 파일에서 네 번째 줄을 추출하는 매우 간단한 작업을 수행했습니다.

awk 'FNR == 4' *.txt >> out_row4

하지만 나머지 파일 처리 작업이 막혀서 제대로 작동하는 최종 솔루션을 생각해낼 수 없었습니다...

처리할 파일 및 줄 수가 매우 많기 때문에 솔루션을 매우 일반적인 방식으로 유지해야 합니다(파일당 5900줄 이상).

참조용 일반 패턴:

  • 항상 각 파일의 처음 3줄을 건너뛰세요.
  • 각 파일의 4번째 줄을 유지하세요
  • 제목 1, 2, 3(...등등)은 다른 파일에서 정확히 동일합니다(따라서 원하는 출력 파일에서 한 번만 보고하면 됩니다).
  • 모든 파일에는 동일한 수의 줄이 포함되어 있습니다.
  • 파일에 알려진 구조적 형식이 없으며 일반 텍스트 파일입니다.

추출하고 재배열하는 일반적인 패턴은 다음과 같습니다.

heading n in the form: 2017243 n 2017243 n
data n file ...

어떤 팁이 있나요?

답변1

애플리케이션DSU 관용어, 필수 POSIX 도구 awk, 정렬 및 잘라내기의 모든 버전을 사용합니다.

$ cat tst.sh
#!/usr/bin/env bash

awk -v OFS='\t' '
    FNR == 1 { fileNr++ }
    FNR >= 4 { print FNR-3, fileNr, $0 }
' "${@:--}" |
sort -n -k1,1 -k2,2 |
awk '($1 % 2) || ($2 == 1)' |
cut -f 3-

$  ./tst.sh file01.txt file02.txt file03.txt
line to keep file 01
line to keep file 02
line to keep file 03
heading 1 in the form: 2017243 01 2017243 01
data 1 file 01
data 1 file 02
data 1 file 03
heading 2 in the form: 2017243 02 2017243 02
data 2 file 01
data 2 file 02
data 2 file 03
heading 3 in the form: 2017243 03 2017243 03
data 3 file 01
data 3 file 02
data 3 file 03

모든 입력을 한 번에 처리해야 하는 위의 유일한 도구는 sort요구 페이지 매김 등을 사용하여 대량의 입력을 처리하도록 설계되었으므로 입력 파일 수는 중요하지 않습니다(ARG_MAX를 초과하지 않는 한). 물론) 또는 얼마나 큰지.

또는 awk를 사용하고 입력 파일이 충분하지 않아 "열린 파일이 너무 많습니다" 오류가 발생한다고 가정합니다.

$ cat tst.awk
BEGIN {
    while ( ! eof ) {
        for ( fileNr=1; fileNr<ARGC; fileNr++ ) {
            if ( (getline vals[fileNr] < ARGV[fileNr]) <= 0 ) {
                eof = 1
            }
        }
        if ( !eof && (++lineNr >= 4) ) {
            if ( lineNr % 2 ) {
                print vals[1]
            }
            else {
                for ( fileNr=1; fileNr<ARGC; fileNr++ ) {
                    print vals[fileNr]
                }
            }
        }
    }
    exit
}

$ awk -f tst.awk file01.txt file02.txt file03.txt
line to keep file 01
line to keep file 02
line to keep file 03
heading 1 in the form: 2017243 01 2017243 01
data 1 file 01
data 1 file 02
data 1 file 03
heading 2 in the form: 2017243 02 2017243 02
data 2 file 01
data 2 file 02
data 2 file 03
heading 3 in the form: 2017243 03 2017243 03
data 3 file 01
data 3 file 02
data 3 file 03

나는 getline대부분의 입력 파일을 한 번에 메모리로 읽는 것을 피하기 위해 위에서 주의를 기울였습니다.http://awk.freeshell.org/AllAboutGetline사용 시기/방법에 대한 자세한 내용을 확인하세요.

답변2

위에서 제공한 패턴을 세 개의 파일에 저장했습니다. 이렇게 하면 awk 필터링을 완료하는 데 필요한 출력을 얻을 수 있습니다.

for i in {4..15}; do awk "FNR == $i" *.txt | sort -u; done

답변3

awk 이외의 것을 사용해도 괜찮다면:

for f in $(ls *.txt) ; do awk 'FNR >=4' $f | egrep "." -n ; done | sort -n | uniq | cut -d: -f2-

성공할 것이다

설명하다:

  • for 루프는 각 파일에서 처음 3줄을 제거하고(awk 사용) 개수를 계산합니다(egrep -n 및 grep 기준으로 모든 문자 사용).
  • 그런 다음 출력은 줄 번호별로 정렬됩니다.
  • 그러면 중복된 헤더 행이 제거됩니다.
  • 마지막으로 줄 번호가 제거됩니다

고쳐 쓰다:

awk는 이미 전체 파일을 반복했으며 출력에 줄 번호를 추가할 수도 있기 때문에 egrep 사용을 제거했습니다(파일을 두 번 읽는 것을 방지).

for f in $(ls *.txt) ; do awk 'FNR >=4 {printf("%s#%s\n", FNR-3, $0)}' $f ; done | sort -n | uniq | cut -d# -f2-

관련 정보