헤더 줄이 포함된 파이프로 구분된 파일이 있습니다 a.txt
. 첫 번째 열에는 파일 이름이 포함됩니다.
a.txt
첫 번째 열에 따라 이름이 결정되는 여러 개의 다른 파일 로 분할하고 싶습니다 . 또한 a.txt
각 파일의 상단에 헤더 행이 반복되기를 원합니다 .
그래서 나는 가지고있다 a.txt
:
filename|count|age
1.txt|1|15
1.txt|2|14
2.txt|3|1
41.txt|44|1
2.txt|1|3
나는 만들고 싶다1.txt
filename|count|age
1.txt|1|15
1.txt|2|14
그리고2.txt
filename|count|age
2.txt|3|1
2.txt|1|3
그리고41.txt
filename|count|age
41.txt|44|1
나는 기본적인 분업을 갖고 있다.
awk -F\| '{print>$1}' a.txt
그런데 제목을 포함하는 방법을 알아내려고 노력 중입니다. 누구든지 도와줄 수 있나요? 감사해요!
답변1
해결책은 헤더를 별도의 변수에 저장하고 $1
새 값(=filename)이 처음 나타날 때 인쇄하는 것입니다.
awk -F'|' 'FNR==1{hdr=$0;next} {if (!seen[$1]++) print hdr>$1; print>$1}' a.txt
- 이렇게 하면 첫 번째 행 전체가
a.txt
변수에 저장되지만hdr
그 외에는 해당 특정 행이 처리되지 않은 상태로 유지됩니다. - 모든 후속 라인에서는 먼저
$1
다양한 값의 발생 횟수를 보유하는 배열에서 해당 값(= 원하는 출력 파일 이름)을 검색하여 이미 발견되었는지 확인합니다. 카운터의 현재 값이 여전히 0이면 표시된 파일에 헤더를 출력한 다음 카운터를 증가시켜 향후 모든 헤더 출력을 억제합니다. 나머지는 스스로 알아냈습니다.seen
$1
$1
$1
부록:
입력 파일이 여러 개 있고 모두 헤더 행이 있는 경우 awk
다음과 같이 호출에 인수로 모두 전달할 수 있습니다.
awk -F'|' ' ... ' a.txt b.txt c.txt ...
그러나 첫 번째 파일에만 헤더 행이 있는 경우 첫 번째 규칙에서 이를 변경해야 합니다 FNR
.NR
경고하다
Ed Morton이 지적했듯이 이 간단한 접근 방식은 다양한 출력 파일의 수가 적은 경우(최대 10개 정도)에만 작동합니다. GNU는 awk
여전히 작동하지만 필요에 따라 백그라운드에서 파일을 자동으로 닫고 열기 때문에 속도가 느려집니다. 다른 awk
구현은 "열린 파일이 너무 많아서" 실패할 수 있습니다.
답변2
이는 awk, sort 및 cut을 사용하여 강력하고 효율적으로 작동합니다.
$ cat tst.sh
#!/usr/bin/env bash
awk 'BEGIN{FS=OFS="|"} {print (NR>1), $1, NR, $0}' "$@" |
sort -t'|' -k1,1n -k2,2 -k3,3n |
cut -d'|' -f4- |
awk '
BEGIN { FS=OFS="|" }
NR == 1 { hdr = $0; next }
$1 != prev {
close(prev)
print hdr " > " $1
prev = $1
}
{ print $0 " > " $1 }
'
$ ./tst.sh a.txt
filename|count|age > 1.txt
1.txt|1|15 > 1.txt
1.txt|2|14 > 1.txt
filename|count|age > 2.txt
2.txt|3|1 > 2.txt
2.txt|1|3 > 2.txt
filename|count|age > 41.txt
41.txt|44|1 > 41.txt
테스트가 완료된 경우 " > "
에만 실제로 출력 파일을 생성하도록 변경되었습니다 .>
선두 awk|sort|cut은 모든 입력 행을 파일 이름($1)으로 그룹화하므로 최종 awk는 한 번에 1개의 출력 파일 내용만 처리하므로 한 번에 1개의 출력 파일만 열립니다. gawk 출력 파일이 12개 정도 있거나 gawk를 사용하여 출력 파일을 열거나 닫아서 실행 속도가 느려지는 경우 더 이상 "열린 파일 이름이 너무 많습니다" 오류로 인해 실패하지 않습니다.
다음은 각 초기 단계에서 발생하는 일입니다. 최종 awk 스크립트에 대한 데이터를 설정하여 1개의 출력 파일만 열고 출력 파일 이름별로 원래 입력 순서를 유지하면서 구문 분석할 수 있도록 합니다.
$ awk 'BEGIN{FS=OFS="|"} {print (NR>1), $1, NR, $0}' a.txt
0|filename|1|filename|count|age
1|1.txt|2|1.txt|1|15
1|1.txt|3|1.txt|2|14
1|2.txt|4|2.txt|3|1
1|41.txt|5|41.txt|44|1
1|2.txt|6|2.txt|1|3
$ awk 'BEGIN{FS=OFS="|"} {print (NR>1), $1, NR, $0}' a.txt |
sort -t'|' -k1,1n -k2,2 -k3,3n
0|filename|1|filename|count|age
1|1.txt|2|1.txt|1|15
1|1.txt|3|1.txt|2|14
1|2.txt|4|2.txt|3|1
1|2.txt|6|2.txt|1|3
1|41.txt|5|41.txt|44|1
$ awk 'BEGIN{FS=OFS="|"} {print (NR>1), $1, NR, $0}' a.txt |
sort -t'|' -k1,1n -k2,2 -k3,3n |
cut -d'|' -f4-
filename|count|age
1.txt|1|15
1.txt|2|14
2.txt|3|1
2.txt|1|3
41.txt|44|1