我有两个文件需要合并为一个。
文件1示例:
gene_1 578
gene_2 565
gene_3 3
gene_4 77
gene_5 8
gene_6 0
gene_7 45
gene_8 67
gene_9 0
gene_10 65
文件2示例:
COG0430 gene_5 gene_9
COG1949 gene_1 gene_3 gene_6
COG5049 gene_2 gene_4 gene_7 gene_10
COG5104 gene_8
输出文件应如下所示:
COG0430 8 0
COG1949 578 3 0
COG5049 565 77 45 65
COG5104 67
有谁知道可以解决这个问题的命令?
答案1
#!/bin/bash
declare -A arr
readarray -t lines < "file1"
for line in "${lines[@]}"; do
arr[${line%% *}]=${line#* }
done
readarray -t lines2 < "file2"
for line in "${lines2[@]}"; do
echo -n "${line%% *} "
for word in $line; do
echo -n "${arr[$word]} "
done
echo
done
不是最干净的 bash,但它确实有效。还要确保你有 bash >= 4.2
答案2
这是一种方法
awk '/^gene/{a[$1]=$2}/^COG/{c=$1;for(b=1;b<=NF;b++){c=sprintf("%s%s%c",c,a[$b],b==NF?"":" ")}print c}' file1 file2
COG0430 8 0
COG1949 578 3 0
COG5049 565 77 45 65
COG5104 67
/gene/{a[$1]=$2}
查找以“gene”开头的任何行,并创建一个项目数组,其中包含第一列的键(例如“gene_1”)和下一列的值(例如“578”)/^COG/
查找任何以“COG”开头的行...c=$1
将变量 c 设置为第一列,例如“COG0430”{c=sprintf("%s%s%c",c,a[$b],b==NF?"":" "
不断将每列的数组条目附加到变量 c 中。如果不是最后一列,请添加空格分隔符。print c
然后只打印完整形式的变量“c”
答案3
你可以试试这个 awk
awk '
NR == FNR {
a[$1] = $2
next
}
{
for ( i = 2 ; i <= NF ; i++)
$i = a[$i]
}
1' file1 file2
或在一根线上
awk 'NR==FNR{a[$1]=$2;next}{for(i=2;i<=NF;i++)$i=a[$i]}1' file1 file2
答案4
perl -ale '
$h{$F[0]}=$F[1],next if @ARGV;
my $k;
print s/\H+/$k++ ? $h{$&} : $&/reg;
' file1 file2
° 读取第一个文件,@ARGV
保存第二个参数,因此返回 true。
%h
°对于 file1 的每一行,使用作为基因名称的键和第二个字段中的相应值填充哈希。
° 对于第二个文件,@ARGV 不包含任何内容,因此将返回 false。最后两行代码将为 file2 的每一行执行。
° 每次读取 file2 的一行时初始化计数变量。然后\H+
应匹配非水平空白字符、iow、字段。从第二个开始,基因名称 => 基因编号的子程序被触发。
具有 Gnu 扩展的 sed 编辑器也可以做到这一点:
sed -Ee '
# store file1 in hold
/^C/!{H;1h;d;}
# place a traveling marker \n\n at $2
s/$/ /
G
s/(\S+\s+)/&\n\n/
# effect gene name => gene number
:a
s/\n\n(\S+)[ ]+((.*\n)?\1\s+([0-9]+))/ \4\n\n\2/
ta
# take away marker and hold portion
s/\n\n.*//
' file1 file2