여러 개의 txt 파일이 있는데 그 중 3개는 다음과 같습니다.
파일 1:
sample input filtered
5809378 1 2
5811151 3 4
5811237 5 6
파일 2:
sample chi tri
5809378 7 8
5811151
5811237 9 10
파일 3:
sample bra doe
5809378 11
5811151 12
5811237 13 14
이 3개 파일을 첫 번째 열(샘플 ID)을 기반으로 1개 파일로 병합하려고 하므로 출력은 다음과 같습니다.
sample input filters chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14
해당 데이터가 없으면 0이 있어야 하며 최악의 경우 빈 탭이 있어야 합니다.
awk 및 Join을 시도했지만 최상의 솔루션을 찾을 수 없습니다. 누구든지 어떤 아이디어가 있습니까?
답변1
내 관점에서 볼 때 file3은 다음 줄 때문에 완전히 정확하지 않습니다.
5811151 12
파일을 읽는 방법에 따라 두 번째 또는 세 번째 열에 숫자 "12"가 있을 수 있습니다(열 구분 기호는 정의되지 않으며 모든 곳에서 다릅니다).
그래도.
a=$(cat file1|awk '{if($2==""){$2="0"};if($3==""){$3="0"}; print $1,$2,$3}'|sort);
for f in file2 file3; do
b=$(cat $f|awk '{if($2==""){$2="0"};if($3==""){$3="0"}; print $1,$2,$3}'|sort);
a=$(join -j 1 <(echo "${a}") <(echo "${b}"));
done;
echo "${a}"|sort -n
출력은 다음과 같습니다
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 12 0
5811237 5 6 9 10 13 14
그래서 우리는
1) 캡처된 모든 파일이 변환됩니다.
cat file|awk '{if($2==""){$2="0"};if($3==""){$3="0"}; print $1,$2,$3}'|sort
누락된 숫자를 "0"으로 바꾸고 행을 정렬합니다.
2) 루프에서 다음 파일을 가져와 이전 결과에 병합합니다.
join -j 1 file_current file_next
따라서 "for f in file2 file3; do" 행은 "for f in file2 file3 file4 file5 file6; do"와 같이 더 많은 파일을 포함하도록 변경될 수 있습니다.
3) 결과를 인쇄하고 문자열 값에 따라 정렬합니다.(먼저 열 이름을 정렬하고 인쇄합니다.) 필요한 경우 여기에서 출력 형식을 지정할 수도 있습니다.
답변2
파일에 탭으로 구분된 열이 있고(세 번째 줄에서 어떤 열이 비어 있는지 알 수 있음 file3
) 예제와 같이 첫 번째 열을 정렬한다고 가정하면 bash 스크립트는 다음과 같습니다.
#!/bin/bash
function fixup() { # Add 0's to blank columns
awk -v cols="$2" 'BEGIN { FS = OFS = "\t" }
{ for (i = 1; i <= cols; i++)
if ($i == "") $i = 0
} 1' "$1"
}
join --header -t$'\t' -j1 \
<(join --header -t$'\t' -j1 <(fixup "$1" 3) \
<(fixup "$2" 3)) \
<(fixup "$3" 3)
할 것:
$ ./combine file1 file2 file3
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14
(실제로 GNU coreutils 버전이 필요합니다 join
).
답변3
시작 파일이 탭으로 구분되어 있고 빈 필드가 여전히 탭으로 구분되어 있다고 가정하면 awk를 사용하여 누락된 열을 0으로 채울 수 있습니다. 예를 들면 다음과 같습니다.
awk -F' ' '!$2{$2=0}!$3{$3=0}{print}' file1 > file1-n
awk -F' ' '!$2{$2=0}!$3{$3=0}{print}' file2 > file3-n
awk -F' ' '!$2{$2=0}!$3{$3=0}{print}' file3 > file3-n
확실하게 awk -F '<TAB>'
. 그런 다음 붙여넣기를 사용하여 병합하고 다른 awk를 사용하여 원하지 않는 열을 필터링할 수 있습니다.
bash-$ paste file1-n file2-n file3-n | awk {'print $1, $2, $3, $5, $6, $8, $9'}
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14
또는 사람의 가독성이 중요한 경우 열을 구분하세요.
bash-$ paste file1-n file2-n file3-n | awk {'printf "%-7s %-5s %-8s %-3s %-3s %-3s %-3s\n", $1, $2, $3, $5, $6, $8, $9'}
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14
답변4
tab
구분 기호 가 있다고 가정하는 또 다른 옵션
0
먼저 복식 사이나 텍스트(예: 제목)나 숫자가 없는 줄 끝에 를 삽입하여 tab
파일을 수정하세요.$
[^[:alnum:]]
TAB=$'\t'; sed -Ei "s/([^[:alnum:]]|${TAB})($|${TAB})/\10\2/g" file*
그럼 그냥 join
그 사람들 이야
join --header file2 file3 | join --header file1 - | column -t
산출
sample input filtered chi tri bra doe
5809378 1 2 7 8 11 0
5811151 3 4 0 0 0 12
5811237 5 6 9 10 13 14