【问题标题】:使用带括号的 awk 进行文件过滤
【发布时间】:2022-01-23 14:16:48
【问题描述】:

我只是在 Linux 中使用awk 过滤文件中的一些内容,这很简单,我能够得到所需的内容,但我几乎无法理解逻辑。我希望有人会为我和像我这样的人说清楚。

1- 文件内容如下...

  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded
  check_ntlm_password:  authentication for user [cnf76628] -> [cnf76628] -> [cnf76628] succeeded

2- 我要做的是获取[] 内的用户 ID,如下所示。

# awk -F'[][]' '/authentication for user/{print $2}' test_file

所以,我无法理解的是,为什么 $2 是用户 ID 作为它退出的第五列,但它需要 $2?这是否意味着我看起来像 authentication for user 的字符串被视为 $1 作为起点?。

任何清晰都会有所帮助。

【问题讨论】:

  • 问题在于[][] 将记录/行与单括号][ 拆分为字段,因此ID 不在第5 个字段中,而是在第二个字段中。如果您删除 -F'[][]',则将使用默认分隔符、空格,然后 ID 将出现在字段 5 中。
  • 请运行以下测试:如果使用 $1 替换 $2 会得到什么?如果使用 $3 替换 $2 会得到什么?
  • 这是一个经典案例,说明你脑海中的第 5 列与代码中的第 5 列之间的差异。在这种情况下,您会失去理智:-)。将您的脚本更改为awk -F'[][]' '/authentication for user/{for (i=1; i<=NF; ++) print i, "<" $i ">"; exit}' test_file,以便您可以查看代码中的列。 /authentication for user/ 测试没有任何用处,因为您发布的示例输入顺便说一句,您可以将其删除。
  • 为了将来参考,请考虑提供一组样本输入数据,其中一些行符合您的处理要求,而另一些则不符合;您当前的样本包含重复 29 次的相同行,因此您的测试 - /authentication for user/ - 似乎是不必要的,因为它发生在每一行;我猜你的 real 数据有一些不包含/authentication for user/ 的行。以及不同的用户 ID(cnf76628 除外),在这种情况下,如果您提供 真实 数据的样本,您可能会得到更好的响应

标签: linux awk


【解决方案1】:

-F 定义字段分隔符 - 默认为空格或制表符。

-F'[abc]' 定义a b c 作为分隔符,因此-F'[[]]' 使[] 分开一个字段。

考虑到这一点,第二个字段位于第一个和第二个分隔符之间。

【讨论】:

    【解决方案2】:

    您的字段分隔符正则表达式匹配[],并且上面的每一行(“记录”)实际上都分为七个字段(请参阅demo):

    当您使用/authentication for user/ 时,它会检查一行中任何位置是否存在authentication for user,即在$0 字段中。但是,authentication for user 出现在字段 1 中,因此您的理解是正确的。

    因此,混淆来自以下事实:[][] 将带有单括号 ][ 的记录/行拆分为字段,因此 ID 不在第 5 个字段中,而是在第二个字段中。如果您删除 -F'[][]',则将使用默认分隔符、空格,然后 ID 将出现在字段 5 中。

    【讨论】:

      【解决方案3】:

      由于您定义的是分隔符,而不是字段,因此该方法因明显原因而失败。

      这是了解您的想法的一种方法。它将带有开头[ 和结尾] 的字段放在行尾,可以通过$(K+1)$(K+2) 等访问。

      $ awk '/authentication for user/{ K=NF; x=NF; 
          for(i=1;i<=NF;i++){ 
            if($i~/^\[/&&$i~/\]$/){ 
              x++; gsub("\[|\]","",$i); $x=$i } } 
          print $(K+1),$(K+3) } END{ print "A full line:\n"$0 }' file
      cnf76628_1 cnf76628_3
      cnf76628_1 cnf76628_3
      cnf76628_1 cnf76628_3
      A full line:
      check_ntlm_password: authentication for user cnf76628_1 -> cnf76628_2 -> cnf76628_3 succeeded cnf76628_1 cnf76628_2 cnf76628_3
      

      数据

      cat file
        check_ntlm_password:  authentication for user [cnf76628_1] -> [cnf76628_2] -> [cnf76628_3] succeeded
        check_ntlm_password:  authentication for user [cnf76628_1] -> [cnf76628_2] -> [cnf76628_3] succeeded
        check_ntlm_password:  authentication for user [cnf76628_1] -> [cnf76628_2] -> [cnf76628_3] succeeded
      

      【讨论】:

        【解决方案4】:

        -F[...] 外括号表示内容 (...) 将以 OR 方式逐一考虑,例如,-F'[ab]' 表示查找字符 @ 987654325@ b

        虽然-F[[]] 似乎表明我们要查找字符[ OR ],但这两个字符(按此顺序)被特殊处理,例如,作为分隔符character class;例如:-F'[[:space:]]'

        为了搜索文字字符 [ OR ] 我们需要在指定它们时切换它们的顺序:-F'[][]'

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-01
          • 1970-01-01
          相关资源
          最近更新 更多