【问题标题】:awk combine conditions and search to print?awk 结合条件和搜索打印?
【发布时间】:2021-03-07 23:13:12
【问题描述】:

这里可能有这样的东西,但我没找到。

为了打印,我要满足两个条件:一种是特定的,一种是开放式的:

首先,

$1 == "SCR"

其次,搜索字符串存在于从$7 到行尾的任何位置。

搜索字符串的示例可能是 _RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf

所以,没有特定的语法,我想我正在寻找的是这样的:

awk '$1 == "SCR" && _RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf exists anywhere in $7 to end of line {print $6}' inputfile.txt

欢迎任何帮助。谢谢。

【问题讨论】:

    标签: awk


    【解决方案1】:

    这可能是您正在寻找的:

    awk '($1 == "SCR") && /^[[:space:]]*([^[:space:]]+[[:space:]]+){6}.*_RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf/{print $6}' file
    

    取决于您是否需要部分或完整的字段匹配,以及您的搜索字符串是否可以包含正则表达式元字符。

    【讨论】:

      【解决方案2】:
      • 用于搜索字符串的参数
      • 使用消隐不可搜索记录的方法(最简洁且可能最快)
      • index() 用于字符串的精确匹配
      awk -v p='_RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf' '
          $1 == "SCR" {
              f=$6
              $1=$2=$3=$4=$5=$6=""
              if (index($0, p))
                  print f
          }
      ' inputfile.txt
      

      只要前导分隔符不是搜索字符串的一部分......我们应该很高兴。

      如果我们希望将此脚本格式化为适合一行:

      awk -v p='_RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf' '$1 == "SCR" { f=$6; $1=$2=$3=$4=$5=$6=""; if (index($0, p)) print f }' inputfile.txt
      

      我决定今天用这个小脚本找点乐子……这是一个填充了副作用的函数变体,它最大限度地减少了全局变量的使用。建议前面的解决方案更简单(也是我们想要的),但是下面的代码既有趣又有教育意义:

      awk -v p='_RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf' '
          function x(v,    f, i) {
              f=$6
              $1=$2=$3=$4=$5=$6=""
              i = index($0, v)
              $0=f
              return i
          }
          $1 == "SCR" && x(p)
      ' inputfile.txt
       
      

      如何解决上述问题:

      • awk 中,我们可以传递比我们在函数定义中指定的更少的参数——函数中未使用的参数基本上是临时变量...您友好的 awk-ers使用 4 空间偏移的约定来标识临时变量。
      • 我们使用与以前基本相同的算法,但不是在成功时使用print f,而是很可爱,只需将f 放回行缓冲区。
      • 那么,print 在哪里???好吧,脚本的最后一行是我们放置 magic...模式成功是到print 行缓冲区。成功! :)
      • 最后一点是关于最后一条语句的执行顺序。 awk 使用&& 的短路评估;因此,我们的 x(p) 函数不可能先触发并在评估 $1 == "SCR" 之前销毁 $1

      我们最喜欢的语言 awk 不是线程语言...所以有一点技巧...我们可以修复这个函数,它的实现既高效又“纯粹”...

      awk -v p='_RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf' '
          function x(v,    b, i) {
              b=$0
              $1=$2=$3=$4=$5=$6=""
              i = index($0, v)
              $0=b
              return i
          }
          $1 == "SCR" && x(p) {
              print $6
          }
      ' inputfile.txt
      

      为什么以上内容很重要?好吧,我们希望我们的函数不改变状态......我们希望我们的函数返回没有副作用......这样我们就可以继续执行而不用担心我们的行缓冲区 - 或其他任何东西 - 已经改变了状态。是的……在最后一个示例中,我们在利用/改变全局状态方面作弊,然后稍后修复它……但最终我们已经修复了它;所以,“没有伤害没有犯规”,嗯?所以......在这个新的实现中,我们实际上可以用 $1 == "SCR" 反转 x(p) 并且没有问题(除了它会更慢)......虽然更复杂的后续程序会受益于使我们的函数“纯” " 因为这种方法更容易思考。

      【讨论】:

      • 感谢您。我不是编码员,但在第一个解决方案旁边,这是我似乎能够遵循的解决方案。我尝试将其折叠为一行并出现语法错误。这就是我尝试过的: awk -v p='_RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf' '$1 == "ACT" {f=$6 $1=$2=$3=$4=$5=$6="" if (index($0, p)) print f} ' 输入文件.txt
      • 是@BabaG -- 感谢您的反馈!我想让代码对你来说可读且平易近人——这就是我把它放在不止一行的原因。不过放在一行上没问题...我们只需要在语句之间放置;...我将在我的答案中添加另一个编辑以向您展示这一点。
      • 谢谢,迈克尔。我确实需要我能得到的所有手持设备;)用你的分号提示玩,发现这行得通: awk -v p='_RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf' '$1 == "ACT" {f=$6; $1=$2=$3=$4=$5=$6="";if (index($0, p))print f}' inputfile.txt
      • @BabaG - 我们都希望玩得开心......并且......取悦。夜巴巴G。
      【解决方案3】:
      awk -v s='_RS1c80952b46129f' '$1=="SCR"{for(i=7;i<=NF;i++) 
                                                if($i==s) {print $6; next}}' file
      

      请注意,这是在寻找完全匹配的字符串,而不是正则表达式。

      【讨论】:

      • 感谢您。实际上,原始版本对我来说效果很好,但修改后的版本也是如此。并感谢以下所有解决方案。我会全部研究的。
      • 如果搜索字符串是唯一的,它们是相同的,新版本更好,因为它在匹配后移动到第二行。可能不是您的情况,但如果您有大量列,则会产生性能差异。
      【解决方案4】:

      gsub( ) 返回它找到的实例数(例如检查gsub(/[ ]+/, "&amp;", $1) &gt;= 6。看到字段之间的空格数在这里并不过分担心,替代方法可以像

      {mawk/mawk2/gawk} -v VAL1='_RS1c80952b46129fc3bbf7b6d35e52f581d5d96edf' 'BEGIN { FS = VAL1 
               
               } ( NF <= 1 ) || ! /^[ \t]*SCR[ \t]/ { next
      
               } { FS = "[ \t]+"; 
      
                      $0 = $1;  if (NF >= 6) { print $6 }; 
                  
                   FS = VAL1; }' 
      

      使用长字符串作为分隔符。在默认情况下,$1=="SCR" 与潜在的前导空白(空格或制表符)相同,即“SCR”,然后再次空白。

      未通过前期项目的预投项目。最后将字段重新设置为标准字段,并检查您是否至少有 6 个这些项目。

      还有 3 种替代方法

      (1) 在最终代码块中进行数组拆分而不是重新处理 seps,或者

      (2) 不要更改 FS,但在 $0 = $1 之后,创建一个重复的正则表达式,它是这个的 5 倍:

             ([^ ]+[ \t]+)
      

      (gawk 提供{5},mawk 并非如此):sub( ) 离开左边 1 次。如果之后您仍然可以找到空白,那么请在此之前将所有内容都拿走。那是你的$6

      (3) 类似于替代方案 (2),但使用 for-loop( ) 5 次将它们从左侧分离开。

      【讨论】:

        猜你喜欢
        • 2020-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多