我有两个不同格式的文件,其中列制表符间隔。我必须比较列column1
, column2
offile1
与file2
.如果它们匹配,我需要将column6
of中的值替换为offile1
中的值。我尝试过使用,但无法替换该值。您能否对下面的代码片段提出建议?column3
file2
awk
awk 'FILENAME == ARGV[1] {
m[$1,$2] = $6;
next;
}
{
if (($1,$2) in m) {
m[$6]= $3; print m[$6];
}
}' file1 file2
top few lines of file1
1201 12011 1 0 0 0 1
1202 12021 1 0 0 0 1
1203 12031 1 0 0 0 1
1204 12041 1 0 0 0 2
1207 12071 1 0 0 0 2
1209 12091 1 0 0 0 1
1210 12101 1 0 0 0 1
1212 12121 1 0 0 0 1
1213 12131 1 0 0 0 1
1214 12141 1 0 0 0 2
top few lines of file2
1201 12011 1
1202 12021 1
1203 12031 1
1204 12041 1
1206 NA 1
1207 12071 2
1208 NA 1
1209 12091 2
1210 12101 2
我想将 file2 中的值分配给 file1 列,因为我想将更新的内容写入另一个文件out.txt
编辑
根据评论尝试了以下代码
awk '{
if (FNR==NR) {
a[FNR]=$1;b[FNR]=$2;c[FNR]=$3}
else {
if (a[FNR] == $1 && b[FNR] ==$2) {
$6=c[FNR]} else {$6=$6};
print $0;
}
}' file2 file1
得到这个输出
1201 12011 1 0 0 1 1
1202 12021 1 0 0 1 1
1203 12031 1 0 0 1 1
1204 12041 1 0 0 1 2
1207 12071 1 0 0 0 2
1209 12091 1 0 0 0 1
1210 12101 1 0 0 0 1
1212 12121 1 0 0 0 1
1213 12131 1 0 0 0 1
1214 12141 1 0 0 0 2
答案1
awk -F"\t" -v OFS="\t" '{
if (FNR==NR) {
a[FNR]=$1;b[FNR]=$2;c[FNR]=$3}
else {
if (a[FNR] == $1 && b[FNR] ==$2) {
$6=c[FNR]} else {$6=$6};
print $0
}
}' file2 file1
我认为这可以完成工作。首先,它将文件 2 的第一、第二和第三列保存到 array a
,b
并分别c
使用索引(仅适用于 file2 中的行)。 Else(仅适用于 file1 中的行)将数组 和 中的值与和进行比较。如果它匹配,则更改数组中的第 6 个字段,否则它将将该值重新分配给相同的值,并将分隔符打印为。FNR
FNR = NR
a
b
$1
$2
c
tab
答案2
另一种非awk
大锤方法
while read f1 f2 f3; do
sed -E -i "s/^($f1\s+$f2.*)([0-9]+)$/\1$f3/" file1;
done < file2
假设最后一个数字是整数。如果不是,则([0-9])$
需要修改为合适的捕获组。
请注意,这依赖于对 file1 进行现场修改,因此需要对副本进行操作。
答案3
看看你的 awk 脚本,你已经有了以不同方式处理每个输入文件的正确想法(尽管在大多数情况下检查是否NR == FNR
工作得更好更快,因为数字比较比字符串比较更快......如果有数千个输入文件,这将很重要一个或两个文件中的输入行的数量)。
但是,有一些问题会阻止您的脚本执行您想要的操作。
您正在以错误的顺序读取文件 - 因为您想要输出 file1 中的行,并将第 6 列替换为 file2 的第 3 列,所以您需要首先读取 file2 来构建数组
m
(索引为$1,$2
from file2 ,值为$3
from文件2)。您正在修改
m[$6]
然后打印它。最多,这将打印一列。
尝试这样的事情:
$ awk 'NR == FNR { m[$1,$2] = $3; next }
($1,$2) in m { $6 = m[$1,$2] }
1' file2 file1
1201 12011 1 0 0 1 1
1202 12021 1 0 0 1 1
1203 12031 1 0 0 1 1
1204 12041 1 0 0 1 2
1207 12071 1 0 0 2 2
1209 12091 1 0 0 2 1
1210 12101 1 0 0 2 1
1212 12121 1 0 0 0 1
1213 12131 1 0 0 0 1
1214 12141 1 0 0 0 2
或者,将NR == FNR
第一行的 替换为原来的FILENAME == ARGV[1]
.
对于每一行file2
(要读取的第一个文件 - 请注意命令行上文件名参数的顺序),它将 $3 存储在数组中m
并跳到下一个输入行。列$1
和$2
用作数组的索引。
然后,在读取file1
(以及后续输入文件,如果有)时,如果($1,$2)
是数组中的索引,它将替换$6
为数组中存储的值m
。
然后它打印当前输入行,无论它是否被修改( 本身的模式1
是 awk 习惯用法/快捷方式,意思是“打印当前输入行” - “1”评估为 true,默认操作是“打印”。 ..所以,实际上“如果 true 为 true 则打印”)
注意:您没有提供示例预期输出,因此我无法验证输出是否与您想要的相匹配(通常,我喜欢将 OP 的示例输出保存到文件中并使用diff
或cmp
验证我的输出是否匹配)。我的 awk 脚本的输出确实匹配我的解释你在问题中要求什么。