주어진 범위의 데이터 블록과 각 블록 내의 주어진 행 범위에서 파일 라인을 추출합니다.

주어진 범위의 데이터 블록과 각 블록 내의 주어진 행 범위에서 파일 라인을 추출합니다.

이 형식의 데이터 파일이 있습니다

1 4
2 0
2 3
3 5
5 3
8 12
2 3
3 5
5 3
0 -1
2 4
33 3

파일에는 12줄이 있으며, 이는 각각 3줄로 구성된 4개의 연속 블록으로 해석되어야 합니다. 예를 들어, 세 번째 블록은

2 3
3 5
5 3

m에서 n까지의 각 블록에서 i에서 j까지의 행을 추출하여 Linux에서 파일로 출력하는 방법은 무엇입니까?

예를 들어 , , , 의 경우 i=2원하는 j=3결과 m=1n=3다음과 같아야 합니다.

2 0
2 3
5 3
8 12
3 5
5 3 

감사해요.

답변1

다음 awk프로그램은 다음을 수행해야 합니다.

awk -v bs=3 -v i=2 -v j=3 -v m=1 -v n=3 '(FNR/bs>m-1) && (FNR/bs<=n) && ((FNR-1)%bs>=i-1) && ((FNR-1)%bs<j)' input.txt 

이렇게 하면 주요 데이터를 awk변수로 프로그램에 가져옵니다.

  • 변수로서의 블록 크기bs
  • 시작 및 끝 블록 번호를 변수로 사용 m하고n
  • 시작 및 끝 줄 번호를 변수로 사용 i하고j

이는 0이 아닌 것으로 평가되는 "rules" 블록 외부의 모든 조건이 현재 행을 인쇄하도록 지시하는 awk논리를 사용합니다 .trueawk

FNR인쇄는 각 파일의 라인 카운터를 나타내는 자동 변수를 기반으로 합니다 . 귀하의 요구 사항은 기본적으로 숫자를 블록 크기로 나누어 블록 번호를 식별 하고 FNR계산 모듈러스로 블록 내의 행을 식별한 다음 FNR(편의상 0부터 시작하여 사용함 인쇄하려는 행에만 적용됩니다.FNR-1true

고쳐 쓰다

시간이 많이 걸리는 작업을 최대한 피함으로써 프로그램의 속도를 높일 수 있습니다. 이렇게 하려면 다음과 같이 프로그램을 수정하면 됩니다.

awk ... 'BEGIN{first=bs*(m-1)+1; last=bs*n}
         FNR<first{next}
         FNR>last{exit}
         ((FNR-1)%bs>=i-1) && ((FNR-1)%bs<j)' input.txt

그러면 먼저 고려해야 할 첫 번째 행과 마지막 행이 결정됩니다.

  • 현재 줄 번호가 첫 번째 블록의 시작 이전이면 즉시 다음 줄로 점프하고 인쇄 여부를 "세밀하게" 확인하기 위한 계산 및 비교를 수행하지 않습니다.
  • 마찬가지로 현재 줄 번호가 고려해야 할 마지막 블록을 초과하면 프로그램을 즉시 종료합니다.
  • "관심 영역" 내에 있는 경우에만 인쇄할 줄을 확인하기 위해 산술 연산이 수행됩니다.

이렇게 하면 계산 노력을 최소한으로 유지할 수 있습니다.

GNU 변형을 사용 awk하고 여러 입력 파일을 인수로 지정한 경우 프로그램을 종료하는 대신 다음 파일로 이동하는 데 nextfile대신 사용하십시오.exit

답변2

GNU sed 및 awk를 사용하는 대체 솔루션:

# Split data into data-blocks
<infile sed '3~3G'                              |

# Only pass blocks m through n onwards
awk 'NR >= m && NR <= n' RS= ORS='\n\n' m=1 n=3 |

# Only print lines i through j within each block
awk '{ for (x=i ; x<=j; x++) print $x }' RS= FS='\n' i=2 j=3

답변3

별도의 스트림 옵션(-s)과 함께 GNU sed를 사용하면 명령줄에서 여러 파일을 별도의 파일로 처리할 수 있습니다.

i=2 j=3 m=1 n=3 G=3
split -l "$G" file
printf '%s\n' x?* |
sed -e "$m,$n!d;${n}q" |
xargs sed -s "$i,$j!d"

답변4

Raku(이전 Perl_6) 사용

raku -e '.join("\n").put for lines.rotor(3)[0..2].map(*.[1..2]);'  

입력 예:

1 4
2 0
2 3
3 5
5 3
8 12
2 3
3 5
5 3
0 -1
2 4
33 3

예제 출력:

2 0
2 3
5 3
8 12
3 5
5 3

위의 내용은 Perl 프로그래밍 언어 계열인 Raku로 작성된 솔루션입니다. 즉, 함께 lines읽고(느리게) rotor-ed(즉, 그룹화) 3하면 각 행이 정확하게 그룹화됩니다(부분 그룹을 반환하려는 경우 끝에 있는 불완전한 그룹은 위 코드로 제거됩니다. 올바른 "부사" 옵션을 추가하세요) , 이와 같이 rotor(3, :partial):).

세 번째 행마다 처음 3개 그룹은 유지되고( [0..2]인덱스 구성 사용) map(*.[1..2])이 세 그룹 내에서 매핑이 수행되어 두 번째 및 세 번째 요소만 반환됩니다(Raku 인덱스와 같은 Perl 계열 언어는 0부터).

위의 코드는 원하는 결과를 반환하지만 프로그래머가 원하는 경우 다음과 같이 라인/참조로 결과를 반환할 수 있습니다.

raku -e '.raku.put for lines.rotor(3)[0..2].map(*.[1..2]);'  file
("2 0", "2 3")
("5 3", "8 12")
("3 5", "5 3")

https://raku.org

관련 정보