我有2个文件如下:
# File 1 has 3 columns:
SampleName Type Position
5R01924 ABC 92184093
5R01028 ABC 15589809
5R01092 ABC 48759348
# File 2 has many columns.
# Column 2 is the Position
# Columns 5 to end are the different SampleNames
A Position B C 5R01924 5R01028 5R01092
1 15589809 2 3 D:E:F:G H:I:J:K L:M:N:O
1 92184093 2 3 P:Q:R:S T:U:V:W X:Y:Z:AA
1 48759348 2 3 AB:AC:AD:AE AF:AG:AH:AI AJ:AK:AL:AM
我想将第四列添加到第一个文件,或者复制文件 1 并将第四列添加到这个新的第三个文件。
第 4 列应包含使用文件 1 中的索引从文件 2 中提取的正确信息。因此,文件 1 的第 1 行表示转到文件 2 的第 2 行并从第 5 列提取信息 (5R01924)。但是,我只想要此信息的 R 部分。所以输出应该是这样的:
# file 3 or append column 4 to file 1
SampleName Type Position Output
5R01924 ABC 92184093 R
5R01028 ABC 15589809 J
5R01092 ABC 48759348 AL
到目前为止我有这样的事情:
while IFS=" " read -r value1 value2 value3
do
awk '$2 == "${value3}" {
# find column # from name of value 1 (save as col variable)
print split(${col},a,":"), a[3]
}' file2 >> file3.txt
done
# where does file 1 go?
请帮忙 :)
答案1
awk 可以自己处理这个问题:这是文件“combine.awk”
# first file, first line
FILENAME == ARGV[1] && FNR == 1 {
for (i=5; i<=NF; i++) head[i] = $i
}
# first file, subsequent lines
FILENAME == ARGV[1] && FNR > 1 {
for (i=5; i<=NF; i++) {
split($i, f, /:/)
value[$2, head[i]] = f[3]
}
}
# second file
FILENAME == ARGV[2] {
print $0, (FNR == 1 ? "Output" : value[$3, $1])
}
然后你像这样调用它
awk -f combine.awk file2 file1 > file3
输出文件包含
SampleName Type Position Output
5R01924 ABC 92184093 R
5R01028 ABC 15589809 J
5R01092 ABC 48759348 AL
答案2
无需调用 bash 来读取文件。
我们可以在 awk 中完成这一切,如下所示:
### sanitize inputs
for f in ./File1 ./File2; do
dos2unix "$f"
done
awk '
!NF || $1 ~ /^#/ {next}
NR==FNR {
for (i=5; i<=NF; i++)
if (NR > 1) {
split($i, t, /:/)
a[sample[i-4],$2] = t[3]
split("", t, ":")
}
else sample[i-4] = $i
next
}
{
k = $1 SUBSEP $3
f = FNR == 1 ? "Output" \
: !(k in a) ? "N/A" \
: a[k]
print $0, f
}
' File2 OFS="\t" File1
输出:
SampleName Type Position Output
5R01924 ABC 92184093 R
5R01028 ABC 15589809 J
5R01092 ABC 48759348 AL
答案3
首先,你的问题很复杂,然后不能指望一个简单的答案。
awk 'BEGIN{IFS="[[:space:]]+";OFS=" ";} NR>1 && NR==FNR {Trr[$3]=$0;Arr[$1]=$3;next} NR>FNR && FNR==1 {for(key in Arr) {for(i=5;i<=NF;i++) {if(key==$i) {nArr[key]=i;break}}}} NR>FNR && FNR>1 {for(tKey in Trr) {if($2==tKey) {for(aKey in Arr) {if(Arr[aKey]==$2) {i=nArr[aKey];Trr[tKey]=Trr[tKey]" "$i;break}}}}}END{for(key in Trr) print Trr[key]}' A B | tr ':' ' ' | awk -F'[[:space:]]+' '{print $1,$2,$3,$6}'
上面的解释:
- IFS和欧福斯:输入和输出文件分隔符。
- [[:space:]]+:由于你的文件分隔符有多个空格,你应该使用它。
- NR是行号从一开始到...
- FNR: 是是文件行号。如果您为 指定多个文件名
awk
,NR从 1 开始,但是,FNR通过文件更改重置为 1 - 下一个,休息很清楚
- {}:您应该在每个块中使用它,以防止解释器产生任何混淆。