将模式匹配字段替换为前一行的字段值

时间:2017-02-27 10:45:22

标签: awk replace pattern-matching field

也许标题不是一个好的描述,但实质上,这是我试图解决的问题:

  • 我的文本文件中包含 n 行和 m 空格分隔符字段
  • 如果行 i 的字段 j 与模式匹配,请将其替换为 i j - 1

我没有被迫使用AWK(在这个例子中是GAWK),但它似乎是这个操作的一个很好的选择。这是我写的sript,它按预期工作,但我想知道是否有更省时的方法来解决问题

{
    if ($0!~/NoData/) {
        split($0, data, " ");
        print $0
    } else {
        split($0, row, " ", seps);
        for(i in row) {if (row[i]~/NoData/) row[i]=data[i]; else data[i]=row[i]; printf "%s%s", row[i], seps[i];}
        printf "\n"                                                                                                                                               
    }
}

作为示例,脚本在此输入文件上运行

0.8147    0.2785    0.9572    0.7922    0.6787    0.7060
0.9058    0.5469    0.4854    0.9595    0.7577    0.0318
0.1270    0.9575    0.8003    0.6557    0.7431    0.2769
0.9134    0.9649    NoData    0.0357    0.3922    0.0462
0.6324    0.1576    NoData    NoData    0.6555    0.0971
0.0975    0.9706    NoData    NoData    0.1712    0.8235

应该产生这个结果

0.8147    0.2785    0.9572    0.7922    0.6787    0.7060
0.9058    0.5469    0.4854    0.9595    0.7577    0.0318
0.1270    0.9575    0.8003    0.6557    0.7431    0.2769
0.9134    0.9649    0.8003    0.0357    0.3922    0.0462
0.6324    0.1576    0.8003    0.0357    0.6555    0.0971
0.0975    0.9706    0.8003    0.0357    0.1712    0.8235

1 个答案:

答案 0 :(得分:2)

awk '{for(i=1;i<=NF;i++){ if($i~/NoData/){ $i=last[i]; } last[i]=$i }  }1' file

如果您想保留原始格式,可以使用下面的内容,如果您有gawk split的第4个参数可能会被使用。

awk '{
       split($0,D,/[^[:space:]]*/);
       s = "";
       for(i=1;i<=NF;i++){ 
            if($i~/NoData/){ $i =  last[i]; } 
            last[i]=$i ; 
            s = s  sprintf("%s%s",D[i],$i) 
       }  
       print s
 }' file

或者设置OFS=""OFS=

awk -v OFS= '{
       split($0,D,/[^[:space:]]*/);
       for(i=1;i<=NF;i++){ 
            if($i~/NoData/){ $i =  last[i]; } 
            last[i]=$i ; 
            $i = sprintf("%s%s",D[i],$i) 
       }  
 }1' file

示例 - 1(保留格式)

$ cat file
0.8147    0.2785    0.9572    0.7922    0.6787    0.7060
0.9058    0.5469    0.4854    0.9595    0.7577    0.0318
0.1270    0.9575    0.8003    0.6557    0.7431    0.2769
0.9134    0.9649    NoData    0.0357    0.3922    0.0462
0.6324    0.1576    NoData    NoData    0.6555    0.0971
0.0975    0.9706    NoData    NoData    0.1712    0.8235

$ awk '{
       split($0,D,/[^[:space:]]*/);
       s = "";
       for(i=1;i<=NF;i++){ 
            if($i~/NoData/){ $i =  last[i]; } 
            last[i]=$i ; 
            s = s  sprintf("%s%s",D[i],$i) 
       }  
       print s
 }' file
0.8147    0.2785    0.9572    0.7922    0.6787    0.7060
0.9058    0.5469    0.4854    0.9595    0.7577    0.0318
0.1270    0.9575    0.8003    0.6557    0.7431    0.2769
0.9134    0.9649    0.8003    0.0357    0.3922    0.0462
0.6324    0.1576    0.8003    0.0357    0.6555    0.0971
0.0975    0.9706    0.8003    0.0357    0.1712    0.8235

示例 - 2(不保留源格式)

默认情况下,它会将单个空格作为输出分隔符,如果您设置OFS,它将覆盖默认值。

$ cat file
0.8147    0.2785    0.9572    0.7922    0.6787    0.7060
0.9058    0.5469    0.4854    0.9595    0.7577    0.0318
0.1270    0.9575    0.8003    0.6557    0.7431    0.2769
0.9134    0.9649    NoData    0.0357    0.3922    0.0462
0.6324    0.1576    NoData    NoData    0.6555    0.0971
0.0975    0.9706    NoData    NoData    0.1712    0.8235

$ awk '{for(i=1;i<=NF;i++){ if($i~/NoData/){ $i=last[i]; } last[i]=$i }  }1' file
0.8147    0.2785    0.9572    0.7922    0.6787    0.7060
0.9058    0.5469    0.4854    0.9595    0.7577    0.0318
0.1270    0.9575    0.8003    0.6557    0.7431    0.2769
0.9134 0.9649 0.8003 0.0357 0.3922 0.0462
0.6324 0.1576 0.8003 0.0357 0.6555 0.0971
0.0975 0.9706 0.8003 0.0357 0.1712 0.8235