【问题标题】:Awk script to add two columns depending on search pattern根据搜索模式添加两列的 awk 脚本
【发布时间】:2022-01-24 20:45:35
【问题描述】:

我有以下 awk 脚本:

#! /usr/bin/awk -f

BEGIN{
FS=OFS="\t";

split("Mtm|^Dept|^Im|^TT|ge[mn]$,^Mini", arr1, ",")
split("Variable Expenses,Fixed Expenses", arr2, ",")
itm="Accounting & Legal";
}

$3<0 && $4~arr1[1] {$7=itm; $8=arr2[1]; print $0}
$3<0 && $4~arr1[2] {$7=itm; $8=arr2[2]; print $0}

产生以下输出:

c_wp_e_2025 2021-05-10  -120.00 8430Ken Jebsen  BILL PAYMENT    12:08-11662 Accounting & Legal  Variable Expenses
c_wp_e_2148 2021-07-27  -90.85  6450Barrie L. Jorgen    BILL PAYMENT    09:31-35651 Accounting & Legal  Variable Expenses
e_wp_e_789  2018-06-12  -190.00 Immigration NZ 11   DEBIT       Accounting & Legal  Variable Expenses
e_wp_e_818  2018-06-29  -153.43 Dept of Home Affa 26    DEBIT   AUD 141.37  Accounting & Legal  Variable Expenses
e_wp_e_839  2018-07-18  -67.47  TT Services New Z 16    DEBIT       Accounting & Legal  Variable Expenses
e_wp_e_2512 2021-07-27  -470.20 Dept Internal Aff 23    DEBIT       Accounting & Legal  Variable Expenses
c_az_262    2021-10-01  -210.45 Mtm Accounting Ltd. Mlm Accounting  Accounting & Legal  Variable Expenses
c_az_421    2021-07-19  -561.20 Paypal *Mtm     Paypal *Mtm Accounting & Legal  Variable Expenses
c_az_1082   2020-11-25  -52.20  Ministryofbusiness  285515Dpsa2A    Mbie    Accounting & Legal  Fixed Expenses
c_az_1110   2020-11-16  -2228.70    Mtm Accounting Ltd. Mlm Accounting  Accounting & Legal  Variable Expenses

这可以按需要工作。然而,除了 itm="Accounting & Legal"(例如 itm="Bank_charges)之外,我还有更多类别,有时还有固定费用和可变费用。在其他时候,其中一个只有在这种情况下,在拆分中创建的数组只有一个值。在这种情况下,主体中的第二条语句将变得未使用。对于每个新类别,都有不同的搜索模式。我是编写 awk 程序的新手,并且一直坚持如何处理这个问题。如何有效地编写它以适应上述情况。

输入(摘录)将是:

c_wp_e_2025     2021-05-10      -120.00 8430Ken Jebsen    BILL PAYMENT    12:08-11662
c_wp_e_2148     2021-07-27      -90.85  6450Barrie L. Jorgen    BILL PAYMENT    09:31-35651
e_wp_e_789      2018-06-12      -190.00 Immigration NZ 11       DEBIT
e_wp_e_818      2018-06-29      -153.43 Dept of Home Affa 26    DEBIT   AUD 141.37
e_wp_e_839      2018-07-18      -67.47  TT Services New Z 16    DEBIT
e_wp_e_2512     2021-07-27      -470.20 Dept Internal Aff 23    DEBIT
c_az_262        2021-10-01      -210.45 Mtm Accounting Ltd.     Mlm     Accounting
c_az_421        2021-07-19      -561.20 Paypal *Mtm             Paypal *Mtm
c_az_1082       2020-11-25      -52.20  Ministryofbusiness      285515Dpsa2A    Mbie
c_az_1110       2020-11-16      -2228.70        Mtm Accounting Ltd.     Mlm     Accounting

Bank_charges 的标准,例如应该是:

split("^Cle|Forei|2 WBC|irnie W| \
wtown W|*M|^Repl|elex|^Unar|lert$,enance$|ebit|A/C|rice$", arr1, ",")
split("Variable Expenses,Fixed Expenses", arr2,",")
itm="Bank_charges

此标准的一些输出将导致:

c_az_1668   2020-03-06  -10.00  Visa Debit Card Fee 4825561******   4823    Bank_charges    Fixed Expenses
c_az_1687   2020-02-28  -8.50   Monthly A/C Fee         Bank_charges    Fixed Expenses
c_az_1688   2020-02-28  -2.50   Clearance Fee           Bank_charges    Variable Expenses
c_az_1785   2020-01-31  -8.50   Monthly A/C Fee         Bank_charges    Fixed Expenses

另一个只有可变费用的类别是:

split("^318|^74 |ASB|^City S|^Fix", arr1,",")
split("Variable Expenses", arr2,",")
itm="Bank_withdrawals"

但是,这根本不适用于上述操作。输入文件中的所有数据都归类为 Bank_withdrawals 并归类为可变费用。

【问题讨论】:

  • 我假设您想根据第四个字段中的关键字对记录进行分类。 arr1arr2itm的内容之间的依赖关系是什么?如果引入itm="Bank_charges" 等其他类别,arr1arr2 将如何变化?那么你的预期输出是什么?
  • arr1 对于其中指定的每个类别都会有所不同。 arr1 搜索所有符合指定搜索模式的交易。 arr2 只能是固定费用、可变费用或两者都取决于类别。例如。公用事业费用可能都是固定费用。最终目标是将所有交易分类,并根据它们是固定费用还是可变费用进行分类。
  • 感谢您的及时反馈。你的回答接近我的预期。那么您能否举一个与Bank_charges 相关的arr1 的示例?它不必是全套。只需几个关键词和相关的输入行就足够了。
  • 谢谢 tshiono。我已经编辑了我的帖子以提供 itm="Bank_charges" 。
  • 我没有看到示例输入和预期输出之间的映射。 Visa Debit Card Fee 4825561******Monthly A/C Fee 是从哪里来的?此外,您的鳕鱼摘录似乎在整个过程中都被换行符和无关的字符/字符串弄乱了。您还发布了一些实际输出,然后是相应的示例输入,但不是该输入的预期输出。请edit 您的问题仅提供 1 个minimal reproducible example 简洁、可测试的示例输入和预期输出以及您现有的代码尝试进行该转换。

标签: awk script


【解决方案1】:

认为这是您正在尝试做的,但它显然未经测试,因为您的问题中没有具体的输入和预期输出样本可供测试:

$ cat tst.sh
#!/usr/bin/env bash

awk '
    BEGIN{
        FS=OFS="\t"

        mkMap("Mtm|^Dept|^Im|^TT|ge[mn]$", "Variable Expenses", "Accounting & Legal")
        mkMap("^Mini", "Fixed Expenses", "Accounting & Legal")
        mkMap("^Cle|Forei|2 WBC|irnie W| wtown W|[*]M|^Repl|elex|^Unar|lert$", "Variable Expenses", "Bank_charges")
        mkMap("enance$|ebit|A/C|rice$", "Fixed Expenses", "Bank_charges")
        mkMap("^318|^74 |ASB|^City S|^Fix", "Variable Expenses", "Bank_withdrawals")
    }

    $3 < 0 {
        found = 0
        for ( re in re2type ) {
            if ( $4 ~ re ) {
                $7 = re2item[re]
                $8 = re2type[re]
                found = 1
            }
        }
        if ( found ) {
            print
        }
    }
    function mkMap(re,type,item) {
        re2type[re] = type
        re2item[re] = item
    }
' "${@:--}"

【讨论】:

  • 感谢 Ed,这是正确的。将其编写为 bash 脚本而不是 awk 脚本 (#!/usr/bin/awk -f) 不会减慢拥有速度吗?
  • @ChristianHick 不客气。不是以任何有意义/引人注目的方式,并且由于stackoverflow.com/a/61002754/1745001 讨论的原因,您永远不应该使用 shebang 来调用 awk。
【解决方案2】:

请您尝试以下方法:

#!/usr/bin/awk -f

BEGIN {
    FS=OFS="\t";

    # enumerate the item, keyword and the statement in order
    itm = "Accounting & Legal"
    key[itm] = "Mtm|^Dept|^Im|^TT|ge[mn]$,^Mini"
    stmnt[itm] = "Variable Expenses,Fixed Expenses"

    itm = "Bank_charges"
    key[itm] = "^Cle|Forei|2 WBC|irnie W|wtown W|*M|^Repl|elex|^Unar|lert$,enance$|ebit|A/C|rice$"
    stmnt[itm] = "Variable Expenses,Fixed Expenses"

    itm="Bank_withdrawals"
    key[itm] = "^318|^74 |ASB|^City S|^Fix"
    stmnt[itm] = "Variable Expenses"

    # initialize key2 and stmnt2 using itm, key and stmnt defined above
    for (itm in key) {
        split(key[itm], a, ",")
        key2[itm,1] = a[1]
        key2[itm,2] = a[2]

        split(stmnt[itm], a, ",")
        stmnt2[itm,1] = a[1]
        stmnt2[itm,2] = a[2]
    }
}

# main loop with the input lines
{
    for (itm in key) {
        for (i = 1; i <= 2; i++) {
            if (key2[itm,i] != "") {
                if ($3 < 0 && $4 ~ key2[itm,i]) {
                    $7 = itm; $8 = stmnt2[itm,i]
                    print $0
                }
            }
        }
    }
}

如果您有更多项目,请将它们附加到键和语句 在引用现有代码的“Bank_charges”行下方。 如果项目有“可变费用”或“固定费用”声明, 只放一个不带逗号的元素。

【讨论】:

  • 谢谢 tshiono。您编写的脚本有效,但是当我在不带逗号的 Bank_charges 下附加 itm="Bank_withdrawals" key[itm] = "^318|^74 |ASB|^City S|^Fix" stmnt[itm] = "Variable Expenses" 时,它不起作用。
  • 感谢您的反馈。通过不起作用,您的意思是相同的行出现两次?如果是这样,我对不带逗号的情况的考虑还不够。现在它是固定的。你能测试一下吗?很抱歉给您带来不便。
【解决方案3】:

如果您是 awk 新手,最好看看写这个长手:

#! /usr/bin/awk -f

BEGIN{ FS=OFS="\t"; }

$3<0 && $4~"Mtm|^Dept|^Im|^TT|ge[mn]$" {$7=;"Accounting & Legal"; $8="Variable Expenses"; print $0}
$3<0 && $4~"^Mini" {$7="Accounting & Legal"; $8="Fixed Expenses"; print $0}

(请原谅错别字,写在我的手机上)

但是我不相信这是你真正要求的,所以我建议循环遍历在开始时创建的数组元素,如下所示:

#! /usr/bin/awk -f

BEGIN{
  FS=OFS="\t";

  els=split("Mtm|^Dept|^Im|^TT|ge[mn]$,^Mini", arr1, ",");
  split("Variable Expenses,Fixed Expenses", arr2, ",");
  split("Accounting & Legal","Accounting & Legal", arr3, ",");
}
for (i=1;i<=els;i++){
  $3<0 && $4~arr1[i] {$7=arr3[i]; $8=arr2[i]; print $0}
}

【讨论】:

  • 谢谢贾德。我尝试了您的建议,但不断收到语法错误:awk: ./script.awk:30: for (i=1;i&lt;=els;i++){ awk: ./script.awk:30: ^ syntax error awk: ./script.awk:30: for (i=1;i&lt;=els;i++){ awk: ./script.awk:30: ^ syntax error awk: ./script.awk:30: for (i=1;i&lt;=els;i++){ awk: ./script.awk:30: ^ syntax error awk: ./script.awk:30: for (i=1;i&lt;=els;i++){ awk: ./script.awk:30: ^ syntax error awk: ./script.awk:31: $3&lt;0 &amp;&amp; $4~arr1[i] {$7=arr3[i]; $8=arr2[i]; print $0} ^ syntax error
  • @ChristianHick 那些语法错误抱怨第 30 行。答案中的脚本没有 30 行,所以无论您尝试执行的是什么,它都不是答案中的脚本。跨度>
猜你喜欢
  • 2015-10-17
  • 2013-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-26
  • 2014-12-14
  • 2016-07-28
相关资源
最近更新 更多