编辑

编辑

我有两个不同格式的文件,其中列制表符间隔。我必须比较列column1, column2offile1file2.如果它们匹配,我需要将column6of中的值替换为offile1中的值。我尝试过使用,但无法替换该值。您能否对下面的代码片段提出建议?column3file2awk

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 ab并分别c使用索引(仅适用于 file2 中的行)。 Else(仅适用于 file1 中的行)将数组 和 中的值与和进行比较。如果它匹配,则更改数组中的第 6 个字段,否则它将将该值重新分配给相同的值,并将分隔符打印为。FNRFNR = NRab$1$2ctab

答案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工作得更好更快,因为数字比较比字符串比较更快......如果有数千个输入文件,这将很重要一个或两个文件中的输入行的数量)。

但是,有一些问题会阻止您的脚本执行您想要的操作。

  1. 您正在以错误的顺序读取文件 - 因为您想要输出 file1 中的行,并将第 6 列替换为 file2 的第 3 列,所以您需要首先读取 file2 来构建数组m(索引为$1,$2from file2 ,值为$3from文件2)。

  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 的示例输出保存到文件中并使用diffcmp验证我的输出是否匹配)。我的 awk 脚本的输出确实匹配我的解释你在问题中要求什么。

相关内容