【问题标题】:awk between 2 pattern search using variables does not appear to work使用变量的 2 个模式搜索之间的 awk 似乎不起作用
【发布时间】:2013-02-11 21:31:40
【问题描述】:

测试文件

cat text.txt 
09:00:00 TESTING
09:00:01 TESTING
09:00:02 TESTING
09:00:03 TESTING
09:00:04 TESTING
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING
09:02:01 TESTING
09:02:02 TESTING
09:02:03 TESTING
09:03:00 TESTING
09:03:01 TESTING
09:03:02 TESTING
09:03:03 TESTING

没有变量的实际模式搜索效果很好:

cat ./text.txt|awk -v start="09:01" -v end="09:02" '/09:01/,/09:02/' text.txt
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING

带有失败变量的模式搜索

awk -v start="09:01" -v end="09:02" '/start/,/end/' text.txt

令人讨厌的 hack 使用 shell echo 包装变量,使其工作

echo "awk -v start="09:01" -v end="09:02" '/$start/,/$end/' text.txt"
awk -v start=09:01 -v end=09:02 '/09:01/,/09:02/' text.txt

start="09:01"; end="09:02"; echo "awk -v start="09:01" -v end="09:02 text.txt" '/$start/,/$end/'"|/bin/sh
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING

关于我做错了什么或者这是否是 awk 中可能的功能的任何想法?

这些建议奏效了,我的结果有些不同:

1.

awk -v start="09:01" -v end="09:02" '$0~start,$0~end' text.txt
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING

2.

awk -v start="09:01" -v end="09:02" 'match($0,start),match($0,end)' text.txt
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING

3.

awk -v start="09:01" -v end="09:02" '$0~start{print}$0~end{print}' text.txt
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING
09:02:01 TESTING
09:02:02 TESTING
09:02:03 TESTING

4.

awk -v start="09:01" -v end="09:02"  '$1~start||$1~end' text.txt
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING
09:02:01 TESTING
09:02:02 TESTING
09:02:03 TESTING

3 和 4 返回完整的结果,前两个一碰到模式就停止

【问题讨论】:

  • 你不能用“~”来表示 $1 的默认分隔符,或者 $0 的任何东西。更别说线上的其他数据了,比如“02:09:01”呢?

标签: bash awk


【解决方案1】:

您需要将变量锚定到行首:

awk -v start="09:01" -v end="09:02" '$0~"^"start,$0~"^"end' text.txt

所以 09:02 匹配 09:02:01 但不匹配 17:09:02。

我个人不会使用这个范围的东西,而是在适当的时候设置/清除/测试一个标志,因为它更具可扩展性。例如尝试其中的每一个,看看打印或不打印分隔线有多容易:

awk -v start="09:01" -v end="09:02" '$0~"^"start{f=1} f; $0~"^"end{f=0}' text.txt
awk -v start="09:01" -v end="09:02" 'f; $0~"^"start{f=1} $0~"^"end{f=0}' text.txt
awk -v start="09:01" -v end="09:02" '$0~"^"start{f=1} $0~"^"end{f=0} f;' text.txt
awk -v start="09:01" -v end="09:02" '$0~"^"end{f=0} f; $0~"^"start{f=1}' text.txt

我从您接受@sudo_Os 的回答中看到,您可能希望获得所有 09:02 时间,而不是停留在第一个时间。如果是这样,只需使用字符串而不是 RE 比较:

$ awk -v start="09:01" -v end="09:02" '$1>=start":00" && $1<=end":59"' file
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING
09:02:01 TESTING
09:02:02 TESTING
09:02:03 TESTING

或者这会给出相同的结果:

$ awk -F: -v start="09:01" -v end="09:02" '$1FS$2>=start && $1FS$2<=end' file

【讨论】:

  • 概念得到我的投票。一旦你有了一个范围的时间,你肯定需要另一个,另一个。跨越24小时。过了一个月。过了一年。顺便说一句,使用 substring($0... 我已经做了很多年了,但从未与其他 AWKers 联系过 :-)
  • @BillWoodger 使用 substr() 很好,只是在这种情况下我不想这样做。我倾向于认为调用函数是低效的,但实际上 awk 中的字符串连接也是低效的,所以它可能没有太大区别。
  • 感谢 Ed :) 通常在当前环境中,日志是日期时间,所以我倾向于留一个空格“09:01”,这样可以确保它捕获 09 而不是 17:09,不过如此未在 awk 中使用锚点,对未来的参考非常有用。很棒的东西,谢谢大家
【解决方案2】:

匹配不应该是:

$ awk -F: -v hour=9 -v start=1 -v end=2 '$1==hour && $2>=start && $2<=end' file
09:01:00 TESTING
09:01:01 TESTING
09:01:02 TESTING
09:01:03 TESTING
09:02:00 TESTING
09:02:01 TESTING
09:02:02 TESTING
09:02:03 TESTING

你不想要所有的09:02:XX 行吗?

【讨论】:

  • 感谢 sudo - 我已经更新了帖子并显示了每种 awk 搜索的结果。
  • 您应该清楚自己想要什么。我和@Thor 的答案给出了不同的结果,他的解决方案为您提供了您所要求的(从09:0109:02 的第一场比赛的打印行),而我的给出您真正想要的(任何行之间有时间)给定范围)。
  • 这个输入怎么样:19:01:01
  • 不,我的意思是“$1~hour”将匹配 19(晚上 7 点)和 09(上午 9 点)。
  • 好点(已修复),您的第一个评论并没有说明您的意思。
【解决方案3】:

要使用 start 和 end 作为模式,您可以使用 ~ 运算符明确告诉 awk:

awk -v start="09:01" -v end="09:02" '$0 ~ start,$0 ~ end'

或者match():

awk -v start="09:01" -v end="09:02" 'match($0,start),match($0,end)'

【讨论】:

    【解决方案4】:
    awk -v start="09:01" -v end="09:02" 'substr($0,1,5) >= start && substr($0,1,5) <= end' test.txt
    

    当时间范围跨越小时的顶部时,这将起作用,并且只会查看小时和分钟。不使用 $1,以避免“命中”具有前导空格但其他匹配的内容。

    坦率地说,我会使用 BEGIN 和一些参数来设置开始/结束。因为你可以在一条线上获得很多东西,但这并不意味着你必须这样做,无论如何对我来说。

    这是我使用的数据:

    09:00:00 TESTING
    09:00:01 TESTING
    09:00:02 TESTING
    09:00:03 TESTING
    09:00:04 TESTING
    09:01:00 TESTING
    09:01:01 TESTING
    09:01:02 TESTING
    09:01:03 TESTING
    09:02:00 TESTING
    09:02:01 TESTING
    09:02:02 TESTING
    09:02:03 TESTING
    09:03:00 TESTING
    09:03:01 TESTING
    09:03:02 TESTING
    09:03:03 TESTING
    02:09:01 toasted
    19:01:01 toasted
      09:01:01 toasted
    20:00:00 toasted 09:01:01
    

    【讨论】:

    • 好的,所以我将它作为一个适当的程序运行并错过了引号。 “语义上”是什么意思?
    • 我在其他类型的 awk 语句中使用了开始/结束,虽然可以很好地捕获日志文件的开始和结束时间,但更难控制与所需给定匹配的特定记录time.The 提供的语句也可以很好地工作。感谢您的输入。 :)
    猜你喜欢
    • 2016-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多