我有多个txt文件,其中3个就像:
file1:
sample input filtered
5809378 1 2
5811151 3 4
5811237 5 6file2:
sample chi tri
5809378 7 8
5811151
5811237 9 10file3:
sample bra doe
5809378 11
5811151 12
5811237 13 14我希望根据第一列:示例ID将这3个文件合并为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注意,如果没有相应的数据,则必须有一个零,或者在最坏的情况下,是一个空选项卡。
我试了一下awk并加入了,但找不到最好的解决方案。有人知道吗?
发布于 2019-12-04 22:21:13
在我看来,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)打印结果,按照字符串数值排序(先排序,然后打印列名)。此外,如果需要,我们可以在这里格式化输出。
发布于 2019-12-05 02:39:51
假设您的文件有选项卡分隔的列(这样您就可以判断哪些列是空的,比如您的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将这样做:$ ./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(确实需要join的GNU核心功能版本)。\t' -j1 \
<(join --header -t将这样做:A2(确实需要D3的GNU核心功能版本)。\t' -j1 <(fixup "$1" 3) \
<(fixup "$2" 3)) \
<(fixup "$3" 3)将这样做:
A2
(确实需要D3的GNU核心功能版本)。
发布于 2019-12-05 18:48:54
另一种方法,假设有一个tab分隔符
首先,通过在双0 S之间插入一个tab,或者在没有文本(即标题)或数字[^[:alnum:]]的情况下,一行以$结尾来修复这些文件
TAB=那就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\t'; sed -Ei "s/([^[:alnum:]]|${TAB})($|${TAB})/\10\2/g" file*那就D6他们
A7
输出
A8
https://unix.stackexchange.com/questions/555650
复制相似问题