【问题标题】:AWK - error in script with count variable OR error in AWK Implementation / version?AWK - 带有计数变量的脚本错误或 AWK 实施/版本中的错误?
【发布时间】:2017-08-25 05:45:44
【问题描述】:
  • Awk 版本:GNU Awk 3.1.1
  • 平台:OpenVMS 8.4-L1
  • Awk 知识:有限

脚本(Awk 一行)。 注意:OpenVMS 参数解析需要引号

gawk "-F" ";" "BEGIN {x = 0} ; x++ {print $0,$1"";""x}" in.file > out.file

**in.file**
file.log;2000
file.log;1999
file.log;1998
file.log;1997

**out.file**
file.log;1999 file.log;2
file.log;1998 file.log;3
file.log;1997 file.log;4

我想要以下内容

file.log;2000 file.log;1
file.log;1999 file.log;2
file.log;1998 file.log;3
file.log;1997 file.log;4

如果我将上面的 awk 命令更改为:...{x = -1}... 我得到

**out.file**
file.log;2000 file.log;0
file.log;1998 file.log;2
file.log;1997 file.log;3

我想知道的是

  1. 其他人是否可以使用其他平台对此进行测试,看看它是否产生相同的输出?
  2. 可能是我正在运行的 awk 版本有问题,或者我的 awk 脚本有什么问题我不理解

在我看来,它确实应该产生一个 file.log;1999 file.log;1 行,但它没有。我很茫然,需要一些指针/awk 教育

提前致谢:-)

【问题讨论】:

    标签: awk gnu openvms


    【解决方案1】:

    您需要使用++x 代替x++x++ 最初计算为0(但将x 增加到1),0 为假,因此不采取行动;第一行没有打印任何内容。

    当您将x 初始化为-1 时,将打印第一行,因为x++ 的计算结果为-1,这是真的;第二个被跳过,因为x 是 0,等等。

    您不需要 BEGIN 块。变量以零(或空字符串)作为值自动激活。事实上,您不需要根据x 是否为零来触发打印;你只是想总是打印一个递增的值x

    所以,在 Mac(类 Unix)系统上,我可以运行:

    $ gawk "-F" ";" '{print $0,$1";"++x}' file.in
    file.log;2000 file.log;1
    file.log;1999 file.log;2
    file.log;1998 file.log;3
    file.log;1997 file.log;4
    $
    

    转换为 VMS 约定,即:

    gawk "-F" ";" "{print $0,$1"";""++x}" file.in
    

    【讨论】:

    • 效果很好 - 谢谢 :-) 我确实尝试过使用 ++x 的东西(尽管我使用了 x++),但我无法正确使用语法,我非常感谢您的帮助。我将尝试您列出的不同组合,以希望巩固它的工作原理。很明显,我对 awk 的新手理解要归咎于您的解决方案也更加优雅:-)
    【解决方案2】:

    为了了解发生了什么,您可以添加额外的输出。

    $ gawk -F\; 'BEGIN {x = 0} {print "step 1: "x} x++ {print "step 2: "x; print $0,$1";"x} {print "step 3: "x"\n"}' in.file
    step 1: 0
    step 3: 1
    
    step 1: 1
    step 2: 2
    file.log;1999 file.log;2
    step 3: 2
    
    step 1: 2
    step 2: 3
    file.log;1998 file.log;3
    step 3: 3
    
    step 1: 3
    step 2: 4
    file.log;1997 file.log;4
    step 3: 4
    

    所以有后增量的效果。

    x {something}{if(x){something}} 相同。因此x 的值将用作调用块{something} 的条件。

    在第一行,在第 1 步,x++ 将返回 0 并递增“x”,这将跳过第 2 步。但在第 3 步,“x”将为 1。

    在第二行,在第 1 步,x++ 将返回 1 并增加“x”。在第 2 步,x 将已经是“2”。这就是你得到的。

    你可以这样修复它:

    gawk -F\; 'BEGIN {x = 0} {print $0,$1";"++x}' in.file
    

    【讨论】:

      【解决方案3】:

      "";"" 是问题所在。尝试。 'BEGIN ... $1";"x ... 代替。您发布的内容相当于。打印 $0,$1; x}即扔掉x。小时

      【讨论】:

      • 我想你会发现转义双引号的 VMS 命令行约定是将它们加倍,而不是像在 Unix 上那样使用反斜杠。我不知道——但如果您将"";"" 序列视为在输出中输入分号的一种方式,它确实有意义。
      • 不幸的是,OpenVMS 命令行需要 "";"" 来输出引号如果我退回到单引号,则输出不包括 ;和 x 的值(即我得到 .log 而不是 .log;1 等)输出正常,除非 x 由于某种原因变为 1
      【解决方案4】:

      由于您对 AWK 不太了解,我可以建议您完全跳过它并切换到 PERL 吗?

      但首先要做的事情。你真正想解决什么问题? 在我看来,您获得了文件名列表(DIR/COL=2/OUT=x.x) 您想使用该列表生成重命名,其中版本号最高的文件变为数字 1,下一个变为 2,依此类推。 对吗?

      我希望不必担心重叠问题,这可能是由于存在版本限制。

      DCL 默认值可以做到这一点。 - 在这里使用 PERL 作为创建一堆文件的便捷方式 - 使用 FILE_ID 显示哪个文件是哪个 就这样吧。

      $perl -e "open X,qq(>file.log;$_) for 1997..2000"
      $dir/file
      FILE.LOG;2000        (59705,105,0)
      FILE.LOG;1999        (46771,399,0)
      FILE.LOG;1998        (42897,980,0)
      FILE.LOG;1997        (24538,519,0)
      $rena/log file.log.* tmp.log;
      %RENAME-I-RENAMED, FILE.LOG;2000 renamed to TMP.LOG;1
      %RENAME-I-RENAMED, FILE.LOG;1999 renamed to TMP.LOG;2
      %RENAME-I-RENAMED, FILE.LOG;1998 renamed to TMP.LOG;3
      %RENAME-I-RENAMED, FILE.LOG;1997 renamed to TMP.LOG;4
      $rena tmp.log;* file.log/log
      %RENAME-I-RENAMED, TMP.LOG;4 renamed to FILE.LOG;4
      %RENAME-I-RENAMED, TMP.LOG;3 renamed to FILE.LOG;3
      %RENAME-I-RENAMED, TMP.LOG;2 renamed to FILE.LOG;2
      %RENAME-I-RENAMED, TMP.LOG;1 renamed to FILE.LOG;1
      $dir/file file.log;*
      FILE.LOG;4           (24538,519,0)
      FILE.LOG;3           (42897,980,0)
      FILE.LOG;2           (46771,399,0)
      FILE.LOG;1           (59705,105,0)
      

      好吗?不需要帮手。只有两个依赖于“;”的命令停止继承的魔法。

      现在让我们看看如何直接在 Perl 中执行此操作。

      $ dir/file
      FILE.LOG;2000        (59705,105,0)
      FILE.LOG;1999        (46771,399,0)
      FILE.LOG;1998        (42897,980,0)
      FILE.LOG;1997        (24538,519,0)
      $ perl -e "for (<file.log;*>) {$i++; $old = $_; s/;\d+/;$i/; rename $old, $_}"
      $ dir/file
      FILE.LOG;4           (24538,522,0)
      FILE.LOG;3           (42897,983,0)
      FILE.LOG;2           (46771,402,0)
      FILE.LOG;1           (59705,108,0)
      

      按步骤分解:

      <xxx> = glob("xxx") = glob(qq(xxx) = wildcard lookup with interpolated string.
      for (<file.log;*>)        # Loop over all files matching pattern, output into $_
      {                         # code block
      $i++;                     # increment for each iteration. start at 1
      $old = $_;                # save the fetched file name
      s/;\d+/;$i/;              # substitute a semicolon followed by numbers 
      rename $old, $_           # Actual rename. Try with PRINT first.
      }                         # end of code block
      

      好吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-25
        • 2016-01-01
        • 2013-03-20
        • 2020-02-06
        • 1970-01-01
        • 1970-01-01
        • 2017-05-07
        相关资源
        最近更新 更多