【问题标题】:awk: Is possible to change the FS variable in block code in an awk script?awk:是否可以在 awk 脚本中更改块代码中的 FS 变量?
【发布时间】:2014-07-28 11:20:14
【问题描述】:

感谢任何帮助。

我在“csv”文件中有以下几行:

11;juan;planA|2014-06-02|3853157|-,planb|2014-08-15|-|-;11111111

12;andrew;planA|2014-07-20|-|-;22222222

我需要产生以下输出:


帐户=11

 Name=juan
 Phone=11111111
 Plan=planA
 Expire=2014-06-02
 used=3853157
 free=
 Plan=planB
 Expire=2014=08-15
 used=
 free=

帐户=12

 Name=andrew
 phone=22222222
 Plan=planA
 Expire=2014-07-20
 used=
 free=

我打印前 3 行的 awk 脚本非常简单:

BEGIN { FS=";";
}
{
print("account=")$1;
print("name=")$2;
print("phone=")$4;       

}
END {
}

所以,我需要一些灯来生成“计划信息”行的逻辑:

我可以将字段 $3 分配给 $0 变量以仅为字段 3 生成一个完整的新行,并将 FS(文件分隔符)更改为 "," 以拆分计划。然后再次将 $1 分配给 $0 并将 FS 现在更改为“|”拥有打印计划线的字段。

我需要知道的是是否可以更改块代码部分中的 FS 变量..还是我完全错了?

谢谢!

【问题讨论】:

  • 你可以使用 split 来实现它..
  • 如果可能,请将输入文件格式更改为合理的格式。设计这种文件格式的人应该被公开羞辱。
  • @tripleee:为什么?这是一个经典的多级方案,其优点是$4总是 是相同的数据项。 PICK/Revelation(虽然已经过时)使用它的多值来做到这一点,ASCII 有不同级别的分隔符(FS/RS/US/GS)等等。顺便说一句,user3717197,FS 是字段分隔符而不是文件分隔符,但我们明白了 :-)
  • 因为理解和操作都很麻烦,而且无法扩展。在当今时代,结构化的、模糊的自文档格式(如 JSON)将是自然的选择。显然,在过去,它们还没有被发明出来。
  • 虽然 JSON 对于 人类 来说可能更容易理解(无需额外的文档),但我怀疑处理它的 awk 代码会更加复杂 :-) 并且“不可能”是一个相当强烈的词,您可以在所有维度上非常轻松地扩展该方案(至少在您用完分隔符之前)。我怀疑,这取决于预期使用数据的内容(人、简单程序、内置 JSON 库的复杂程序等)。

标签: variables awk scripting fs


【解决方案1】:

您不需要弄乱字段分隔符,awk 为您提供类似的功能,通过在字段上使用 split 来获取数组,例如:

split($3,f3,"|");

以下记录显示了这一点:

pax> echo "x1;x2a|x2b|x2c;x3" | awk -F';' '{split($2,arr,"|");print $1" "arr[2]}'
x1 x2b

您的特定案例稍微复杂一些,因为您需要将$3 拆分为计划,然后对于这些计划中的每个,拆分以提取四个部分的信息。以下脚本似乎可以正常工作:

BEGIN {FS = ";"}
{
    print "Account="$1;
    print "  Name="$2;
    print "  Phone="$4;
    nplans = split ($3, plans, ",");
    for (i = 1; i <= nplans; i++) {
        split (plans[i], planinfo, "|");
        if (planinfo[3] == "-") {planinfo[3] = ""};
        if (planinfo[4] == "-") {planinfo[4] = ""};
        print "  Plan="planinfo[1];
        print "    Expire="planinfo[2];
        print "    Used="planinfo[3];
        print "    Free="planinfo[4];
    }
}

输出:

Account=11
  Name=juan
  Phone=11111111
  Plan=planA
    Expire=2014-06-02
    Used=3853157
    Free=
  Plan=planb
    Expire=2014-08-15
    Used=
    Free=
Account=12
  Name=andrew
  Phone=22222222
  Plan=planA
    Expire=2014-07-20
    Used=
    Free=

【讨论】:

  • 我也有同样的想法……很好!
  • 如果您希望保证输出中计划的顺序与输入顺序相同,请使用for (i=1;i in f3;i++) 而不是for (i in f3)。不确定 f3f3x 是很棒的变量名(为什么不是 plansplan 或类似的名称?)但是 +1 的方法!哦,split() 的第三个参数是一个 RE,所以当一个常量应该由 /s 而不是 "s 分隔时,所有那些尾随分号都是多余的。
  • 所有优点,@Ed,我已经采纳了你的一些建议。对于第三个参数,当我使用单个字符时,我更喜欢引号,并且作为 C 偏执狂,我喜欢分号 :-)
【解决方案2】:

也许你可以使用正则表达式来分隔字段:

awk -F'[;|,]' '{i=1;
            print "account="$i;i++;
            print "Name="$i;i++;
            print "Phone="$NF;
            while(i < NF){
              print "Plan="$i;i++;
              print "Expire="$i;i++;
              print "used="($i!="-"?$i:"");i++;
              print "free="($i!="-"?$i:"");i++;
            }
            print "";}' input.txt

这至少适用于您的示例输入。我假设示例输入中没有空行。

输出:

account=11
Name=juan
Phone=11111111
Plan=planA
Expire=2014-06-02
used=3853157
free=
Plan=planb
Expire=2014-08-15
used=
free=

account=12
Name=andrew
Phone=22222222
Plan=planA
Expire=2014-07-20
used=
free=

输入:

11;juan;planA|2014-06-02|3853157|-,planb|2014-08-15|-|-;11111111
12;andrew;planA|2014-07-20|-|-;22222222

【讨论】:

    猜你喜欢
    • 2016-04-24
    • 1970-01-01
    • 2016-10-28
    • 2019-04-15
    • 1970-01-01
    • 2014-06-27
    • 2020-06-03
    • 2023-03-30
    • 2012-08-12
    相关资源
    最近更新 更多