【问题标题】:Need Help in understanding AWK script logic [closed]在理解 AWK 脚本逻辑方面需要帮助 [关闭]
【发布时间】:2019-05-24 20:36:20
【问题描述】:

我需要帮助来理解我们的一位同事过去用 AWK 编写的以下代码逻辑。 任何具有良好 AWK 知识的人都可以帮助我理解这段代码。

谢谢, 桑迪普

sed -i 's/\r//g' $1 $2
sed -i 's/,/;/g' $1 $2
awk -F"|" '{if(FILENAME=="Parameter.txt"){a[$1]=NR;aa[NR]=$1;d=NR;if(NR==1){e=$1}else{e=e","$1};}
                        else if(FILENAME=="Traffic.csv"){h[FNR","$2]=$3;x[FNR","$4]=$5;k[FNR","$2","$3","$4","$5]=$1;y=FNR;}
                        else if(FILENAME=="Filter.txt"){for(i=1;i<=NF;i=i+3){if($(i+1)!="ne"){FE[FNR","$i]=$(i+2)}else{FNE[FNR","$i]=$(i+2)}};FILTER=FNR;FC[FNR]=(NF/3);}
                        else{
                                if(g==""){print e",TRAFFIC_CASE";g=1};
                                for(i=1;i<=d;i++){c[i]=""};l="";m="";z="";FINAL="";for(j=1;j<=FILTER;j++){FI[j]=""};
                                for(i=1;i<=NF;i++){
                                                                        split($i,b,"=");
                                                                        if(a[b[1]]!=""){c[a[b[1]]]=b[2];};
                                                                        for(j=1;j<=y;j++){
                                                                                if(h[j","a[b[1]]]==b[2] && h[j","a[b[1]]]!=""){l=a[b[1]]","b[2]};
                                                                                if(x[j","a[b[1]]]==b[2] && x[j","a[b[1]]]!=""){z=a[b[1]]","b[2]};
                                                                                if(k[j","l","z]!=""){m=k[j","l","z]};};
                                                                        };
                                if(substr(FILENAME,20,3)=="SVC"){Q[c[a[MSISDN]]]=1}
                                else if(Q[c[a[MSISDN]]]!=1){
                                        for(i=1;i<=d;i++){
                                                                                if(i==1){f=c[1];}else{f=f","c[i]};
                                                                                if(c[i]==""){c[i]="B"};
                                                                                for(j=1;j<=FILTER;j++){
                                                                                        if(FE[j","i]!=""){if(FE[j","i]==c[i] && (FI[j]=="" || FI[j]<=FC[j])){FI[j]=FI[j]+1;}else{FI[j]=FI[j]-1;}};
                                                                                        if(FNE[j","i]!=""){if(FNE[j","i]!=c[i] && (FI[j]=="" || FI[j]<=FC[j])){FI[j]=FI[j]+1;}else{FI[j]=FI[j]-1;}};
                                                                                        };
                                                                                };
                                                                        }
                                for(j=1;j<=FILTER;j++){if(FI[j]==FC[j]){FINAL=1};};
                                if(FINAL!=1){print f","m;};
                                };
                        }' Parameter.txt Traffic.csv Filter.txt $2 $1

【问题讨论】:

  • 在 awk 脚本(参见手册页)上运行 gawk -o- 以漂亮地打印它。格式化后,您会更好地理解它。

标签: shell awk


【解决方案1】:

这是您的代码,由gawk -o 漂亮打印,以使其可读(以防您没有 gawk),希望您可以自己弄清楚:

{
    if (FILENAME == "Parameter.txt") {
        a[$1] = NR
        aa[NR] = $1
        d = NR
        if (NR == 1) {
            e = $1
        } else {
            e = e "," $1
        }
    } else if (FILENAME == "Traffic.csv") {
        h[FNR "," $2] = $3
        x[FNR "," $4] = $5
        k[FNR "," $2 "," $3 "," $4 "," $5] = $1
        y = FNR
    } else if (FILENAME == "Filter.txt") {
        for (i = 1; i <= NF; i = i + 3) {
            if ($(i + 1) != "ne") {
                FE[FNR "," $i] = $(i + 2)
            } else {
                FNE[FNR "," $i] = $(i + 2)
            }
        }
        FILTER = FNR
        FC[FNR] = (NF / 3)
    } else {
        if (g == "") {
            print e ",TRAFFIC_CASE"
            g = 1
        }
        for (i = 1; i <= d; i++) {
            c[i] = ""
        }
        l = ""
        m = ""
        z = ""
        FINAL = ""
        for (j = 1; j <= FILTER; j++) {
            FI[j] = ""
        }
        for (i = 1; i <= NF; i++) {
            split($i, b, "=")
            if (a[b[1]] != "") {
                c[a[b[1]]] = b[2]
            }
            for (j = 1; j <= y; j++) {
                if (h[j "," a[b[1]]] == b[2] && h[j "," a[b[1]]] != "") {
                    l = a[b[1]] "," b[2]
                }
                if (x[j "," a[b[1]]] == b[2] && x[j "," a[b[1]]] != "") {
                    z = a[b[1]] "," b[2]
                }
                if (k[j "," l "," z] != "") {
                    m = k[j "," l "," z]
                }
            }
        }
        if (substr(FILENAME, 20, 3) == "SVC") {
            Q[c[a[MSISDN]]] = 1
        } else if (Q[c[a[MSISDN]]] != 1) {
            for (i = 1; i <= d; i++) {
                if (i == 1) {
                    f = c[1]
                } else {
                    f = f "," c[i]
                }
                if (c[i] == "") {
                    c[i] = "B"
                }
                for (j = 1; j <= FILTER; j++) {
                    if (FE[j "," i] != "") {
                        if (FE[j "," i] == c[i] && (FI[j] == "" || FI[j] <= FC[j])) {
                            FI[j] = FI[j] + 1
                        } else {
                            FI[j] = FI[j] - 1
                        }
                    }
                    if (FNE[j "," i] != "") {
                        if (FNE[j "," i] != c[i] && (FI[j] == "" || FI[j] <= FC[j])) {
                            FI[j] = FI[j] + 1
                        } else {
                            FI[j] = FI[j] - 1
                        }
                    }
                }
            }
        }
        for (j = 1; j <= FILTER; j++) {
            if (FI[j] == FC[j]) {
                FINAL = 1
            }
        }
        if (FINAL != 1) {
            print f "," m
        }
    }
}

现在它的格式已清晰明了,第 2 步是您尝试理解脚本时将所有变量重命名为它们真正代表的任何内容,例如a[$1]=NR -> param2lineNr[$1]=NRaa[NR]=$1 -> lineNr2param[NR]=$1 或类似的,具体取决于 $1 在该 Parameter.txt 文件中的内容。您还应该引入一些中间命名的变量,这样您就不会在下次阅读代码时试图弄清楚像 Q[c[a[MSISDN]]] 这样的结构实际上意味着什么(顺便说一句,这对我来说很像一个错误,因为 MSISDN 是未初始化的变量——作者可能是指Q[c[a["MSISDN"]]],但肯定是idk)。一旦您设法对所有变量执行此操作,整个脚本的含义就应该很清楚了。玩得开心!

【讨论】:

  • 谢谢 ..但是你是如何在这个文件上执行 gawk -o 的:我也试过了,得到了下面的 o/p [root@meylvvmnmt01 /tmp/script]# gawk -o Pre_CDR_1.sh Usage: gawk [POSIX or GNU style options] -f progfile [--] file ... Usage: gawk [POSIX or GNU style options] [--] 'program' file ... POSIX options: GNU long options: (standard)
  • 查看手册页和/或运行gawk --help,不难弄清楚。另外我猜Pre_CDR_1.sh 是您的 shell 脚本,而不是存储在其中的 awk 脚本。你会想在你的 awk 脚本上运行 gawk,而不是你的 shell 脚本。
【解决方案2】:

我们在文件中有参数、流量案例和过滤器...这是一个足够大的脚本,它也希望在一个独立的文件中。

我的过程:

  1. 我在 vim 中重新格式化并删除了结果
  2. 我通过第一组括号外的模式匹配消除了一个嵌套。
  3. 我在数组中看到"," 的串联...可以为此使用 SUBSEP(经过进一步重构,可能可以消除 SUBSEP 定义...不相关
  4. 那些我看到检查if (foo[bar] == "")的地方,我将其替换为更直观的if (bar in foo)
  5. 我开始用 s/\&lt;x\&gt;/something_x/g 替换——vim 非常适合这个,因为你可以使用 \&lt; \&gt; 隔离变量名...
  6. 我用split("", arr) 替换了空白数组
  7. 我看到 b[1] 是键,b[2] 是值...最好创建中间变量以使流量匹配部分更具可读性。
  8. 遍历每个变量开始发现未使用的变量,例如 aa
  9. 我将foo = foo + 1 更改为foo++
  10. 我颠倒了if 语句中似乎合适的逻辑条件,并去掉了多余的{}
  11. 我对过滤位进行了一些重构,以减少数组查找的次数。

这是我的猜测:

#! /usr/bin/awk -f

BEGIN {
    FS = "|"
    fileno = 0
    SUBSEP = ","
}

FILENAME == "Parameter.txt" {
    param[$1] = NR
    param_sz = NR
    if (FNR == 1)
        param_list = $1
    else
        param_list = param_list "," $1
    next
}

FILENAME == "Traffic.csv" {
    traffic_h[FNR, $2] = $3
    traffic_x[FNR, $4] = $5
    traffic_key[FNR, $2, $3, $4, $5] = $1
    traffic_sz = FNR
    next
}

FILENAME == "Filter.txt" {
    for (i = 1; i <= NF; i += 3) {
        if ($(i + 1) == "ne")
            filter_ne[FNR, $i] = $(i + 2)
        else
            filter_eq[FNR, $i] = $(i + 2)
    }
    filter_sz = FNR
    filters[FNR] = (NF / 3)
    next
}

fileno == 0  {
    print param_list ",TRAFFIC_CASE"
    fileno = FNR
}

{
    split("", case)
    l = ""
    traffic_match = ""
    z = ""
    final_filter = 0
    split("", filtered)

    for (i = 1; i <= NF; i++) {
        split($i, b, "=")
        key = b[1]
        val = b[2]
        if (key in param) {
            this_param = param[key]
            case[this_param] = val
            for (t = 1; t <= traffic_sz; t++) {
                if ((t, this_param == val && traffic_h[t, this_param]) in traffic_h)
                    l = val
                if ((t, this_param == val && traffic_x[j, this_param]) in traffic_x)
                    z = val
                if ((t, this_param, l, this_param, z) in traffic_key)
                    traffic_match = traffic_key[t, this_param, l, this_param, z]
            }
        }
    }
    if (substr(FILENAME, 20, 3) == "SVC") {
        svc_case[case[param["MSISDN"]]] = "" # << MSISDN was = "" so... arbitrary string should be OK or... should fix your bug?
    }
    if (!(case[param["MSISDN"]] in svc_case)) {
        for (p = 1; p <= param_sz; p++) {
            if (p == 1)
                case_list = case[1]
            else
                case_list = case_list "," case[i]
            if (!(p in case))
                case[p] = "B"
            for (f = 1; f <= filter_sz; f++) {
                if ((f, p) in filter_eq) {
                    if (filter_eq[f, p] == case[p] && (!f in filtered) || filtered[f] <= filters[f]))
                        ++filtered[f]
                    else
                        --filtered[f]
                } else if ((j, i) in filter_ne) {
                    if (filter_ne[f, p] != case[p] && (!(f in filtered) || filtered[f] <= filters[f]))
                        ++filtered[f]
                    else
                        --filtered[f]
                }
            }
        }
    }
    for (f = 1; f <= filter_sz; f++)
        if (filtered[f] == filters[f])
            final_filter = 1
    if (!final_filter)
        print case_list "," traffic_match
}

所以,我很可能出错了,因为我没有 I/O 可用于测试用例 - 但您可以重复我的步骤来找出现实。我会再处理一下那个过滤片段......我会检查“MSISDN”(就像 Ed 建议的那样),看看你是否觉得这很有趣......

另一件看起来很可疑的事情是,您表面上是在尝试使用“|”解析 .csv 文件作为分隔符...这可能行不通。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-02
    • 2010-09-14
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2012-07-12
    • 2013-12-14
    相关资源
    最近更新 更多