파일이 여러 개 있고 각 파일의 첫 번째 열을 기준으로 병합해야 합니다.
파일 1:
foo 12
jhdfeg 25
kjfdgkl 37
파일 2:
foo 23
jhdfeg 45
파일 3:
foo 35
djhf 37
출력은 다음과 같아야합니다
file1 file2 file3
foo 12 23 35
jhdfeg 25 45 0
kjfdgkl 37 0 0
djhf 0 0 37
답변1
앗방법:
joiner.awk
스크립트:
#!/bin/awk -f
BEGIN {
f1=ARGV[1]; f2=ARGV[2]; f3=ARGV[3] # the 1st, 2nd and 3rd file names respectively
printf("%10s\t%s\t%s\t%s\n", "", f1, f2, f3) # printing header
}
{ a[$1][FILENAME]=$2 } # accumulating values
END {
for (i in a) {
printf("%-10s\t%d\t%d\t%d\n", i, a[i][f1], a[i][f2], a[i][f3])
}
}
용법:
awk -f joiner.awk file1 file2 file3
산출:
file1 fil2 file3
kjfdgkl 37 0 0
foo 12 23 35
djhf 0 0 37
jhdfeg 25 45 0
답변2
perl -F'\s+' -lane '
$. == 1 and @ARGC = ($ARGV, @ARGV); # initialize the @ARGC array
exists $h{$F[0]} or $h[keys %h] = $F[0]; # needed to remember order
$h{$F[0]}->[@ARGC-@ARGV-1] = $F[1]; # populate hash
END {
$, = "\t"; # set the OFS to TAB
print q//, @ARGC; # print the first line with filenames
for my $key (@h) { # print remaninig lines with data
print $key,
map { $h{$key}->[$_] // 0 } 0 .. $#ARGC;
}
}
' file1 file2 file3 # ... you can give as many files here
산출
file1 file2 file3
foo 12 23 35
jhdfeg 25 45 0
kjfdgkl 37 0 0
djhf 0 0 37
답변3
귀하의 예와 같이 파일이 3개 있는 경우
join
마법을 사용하여 이 작업을 수행할 수 있습니다. 먼저 탭으로 구분된 파일 이름을 출력 파일에 씁니다.
for i in File*; do printf "\t%s" "$i" >> RES; done
실제 결과에 대해 빈 줄을 추가합니다.
printf '\n' >> RES
join
on을 사용 File1
하고 File2
출력을 임시 파일로 리디렉션합니다.
join -a1 -a2 -e0 <(sort File1) -o 0 1.2 2.2 <(sort File2) > TEMP_FILE
이제 위 명령의 출력을 다시 사용하십시오 File3
(여기서 파이프( )를 사용할 수도 있습니다 |
).
join -a1 -a2 -e0 <(sort TEMP_FILE) -o 0 1.2 1.3 2.2 <(sort File3) >> RES
공백을 탭으로 바꾸십시오 RES
.
tr ' ' '\t' < RES > FINAL_RES
결과는 다음 위치에 있습니다 FINAL_RES
.
$ cat FINAL_RES
File1 File2 File3
foo 12 23 35
jhdfeg 25 45 0
kjfdgkl 37 0 0
답변4
파일 수와 관계없이 보다 일반적인 접근 방식은 다음과 같습니다 sed
.
sed '1{x;s/$/_/;x;}
/foo/{x;s/_/ 0_/g;x;}
G;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\30_\4\1\3\2_/
$! {h;d;}
s/[^_]*_//
y/_/\n/' file*
이는 foo
예제에서 볼 수 있듯이 해당 줄로 시작하는 모든 파일에 의존합니다.
sed
이제 작동 방식, 패턴 공간, 공간 유지에 대한 기본 사항을 알았으므로 설명은 다음과 같습니다.
주요 아이디어는 예약된 공간에 전체 출력 테이블을 구축하는 것입니다. 각 행에 대해 예약된 공간에는 해당 지점의 테이블과 새 행에 필요한 템플릿 행이 포함됩니다. _
처리 중에 줄 구분 기호로 사용합니다 . 이제 단계별로:
1{x;s/$/_/;x;}
그러면 _
템플릿 줄의 시작 부분으로 단일을 사용하여 예약된 공간이 초기화됩니다.
/foo/{x;s/_/ 0_/g;x;}
/foo/
foo
새 파일의 시작을 나타내는 포함 줄을 지정합니다 . 이 경우 다음 명령이 실행됩니다 {}
. 예약된 공간의 모든 행(실제 테이블 행 및 템플릿 행)이 0
추가됩니다. 나중에 해당 줄에 대한 키워드를 발견하면 0
올바른 숫자로 대체됩니다. 키워드가 나타나지 않으면 0
유지됩니다.
G;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
'G'는 예약된 공간을 패턴 공간에 추가합니다. 명령 s
은 네 부분으로 구성됩니다 . 첫 번째 부분에는 키워드가 포함되고, 두 번째 부분에는 값이 포함되며, 세 번째 부분에는 키워드가 두 번째 나타날 때까지(역 참조 ) \(\)
개행 문자 뒤의 모든 항목이 포함됩니다(따라서 이는 예약된 공간에서 추가된 테이블입니다). \1
. 네 번째 항목은 마지막 항목을 제외한 행의 모든 항목을 소유합니다 0
. 따라서 해당 키워드가 포함된 기존 행을 찾고 0
모든 것을 개행 문자에 넣고 업데이트된 테이블을 유지합니다.
s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\30_\4\1\3\2_/
또 다른 일치 항목에는 newline이 포함되어 있으므로 \n
테이블에서 키워드를 찾지 못했다는 것을 알 수 있습니다(그렇지 않으면 이전 줄에서 줄바꿈이 제거되었을 것입니다. 따라서 이번에는 키워드로 구성된 새 줄을 끝에 추가합니다. 이것이 바로 템플릿 행의 비결입니다. 0
새 파일마다 열을 추가하므로 열을 제거하면 0
각 파일에 대해 키워드가 없는 열이 하나씩 있게 됩니다.0
$! {h;d;}
마지막 행이 아닌 경우 수정된 테이블을 다시 예약된 공간( h
)으로 이동하고 다시 시작합니다( d
).
s/[^_]*_//
마지막 행의 경우 템플릿 행이 제거됩니다.
y/_/\n/
_
이는 개행 문자를 대체합니다 . 또한 원하는 경우 공백을 탭으로 바꿀 수 있습니다.
편집하다
모든 파일이 해당 줄로 시작한다는 가정이 잘못된 경우 각 파일의 시작 부분에 추가 줄을 추가하고 전체 콘텐츠를 다음으로 스트리밍하는 등 새 파일이 시작되는 시기를 foo
알 수 있는 다른 방법이 필요합니다 .sed
sed
for file in file*; do
echo Start of $file
cat $file
done | sed '1{x;s/$/__/;x;}
/Start of/{G;s/_/ 0_/g;s/Start of \(.*\)\n\([^_]*\)_\([^_]*\) 0/\2_\3 \1/;x;d;}
G;l;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
l;s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\3 0_\4\1\3\2_/
$! {h;d;}
s/[^_]*_//
y/_/\n/'
이 버전은 또한 모든 파일 이름을 열 헤더로 사용하여 테이블의 헤더 행을 생성합니다.