이 형식의 데이터 파일이 있습니다
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=1
는 n=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
논리를 사용합니다 .true
awk
FNR
인쇄는 각 파일의 라인 카운터를 나타내는 자동 변수를 기반으로 합니다 . 귀하의 요구 사항은 기본적으로 숫자를 블록 크기로 나누어 블록 번호를 식별 하고 FNR
계산 모듈러스로 블록 내의 행을 식별한 다음 FNR
(편의상 0부터 시작하여 사용함 인쇄하려는 행에만 적용됩니다.FNR-1
true
고쳐 쓰다
시간이 많이 걸리는 작업을 최대한 피함으로써 프로그램의 속도를 높일 수 있습니다. 이렇게 하려면 다음과 같이 프로그램을 수정하면 됩니다.
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")