【问题标题】:How to grep lines starting with a digit or white space如何grep以数字或空格开头的行
【发布时间】:2015-02-09 20:54:31
【问题描述】:

我需要在我的日志文件中统计每小时的消息数。每个日志文件行前面都有时间戳。因此,我使用以下 'for' 和 'grep' 命令来执行此操作 -

for i in `seq 0 23`
do egrep "$i:[0-9][0-9]:[0-9][0-9] <some_pattern>" filename | wc -l
done

这将为我提供从 0 到 23 的每小时消息数。

但是,这不适用于5:23:32 等单个数字小时,因为它前面有一个空格。那么 grep 必须是 -

egrep " $i:[0-9][0-9]:[0-9][0-9] <some_pattern>" filename | wc -l

如果不是,它将错误地匹配以 15:23:32 开头的行

那么我如何告诉 grep 一个数字前面只能有空格或行首。

【问题讨论】:

    标签: regex bash grep


    【解决方案1】:

    使用 egrep

    for i in `seq 0 23`; do egrep -c "^[[:space:]]*$i:[0-9][0-9]:[0-9][0-9] <some_pattern>" 'filename'; done
    

    ^[[:space:]]*$i:[0-9][0-9]:[0-9][0-9] 这将告诉 egrep 从行首开始匹配。如果该行以行首的空格开头或仅以您的模式开头,则 grep 将匹配它。这也将告诉 grep 匹配而不是贪婪匹配。

    例如

    使用带有模式的命令来查找5:23:32,(其中$i=5)我们得到

    5:23:23
       15:23:23
    

    使用上面的命令,我们得到

     5:23:23
    

    grep 带有一个 -c 选项来计数

    您也可以使用 grep 的 -c 选项而不是通过管道连接到 wc -l

    例子

    for i in `seq 0 23`; do egrep -c "^[[:space:]]*$i:[0-9][0-9]:[0-9][0-9] <pattern>" 'filename'; done
    

    【讨论】:

      【解决方案2】:

      我想我可以摆脱你的for 循环。如果该时间(而不是日期)从每一行开始,这将起作用:

      $ awk -F : '/some_pattern/ { print $1 }' file |sort |uniq -c
      

      这会搜索您想要的模式(有点像grep),然后打印第一个元素(由冒号分隔),即小时。然后对其进行排序并计算重复的唯一元素并将其显示在标准输出中。

      但是,假设您的日志看起来像 /var/log/syslog,其中的行看起来像这样:

      Feb  9 01:23:45 mycomputer service[PID]: details...
      

      在这种情况下,你必须告诉 AWK 去哪里寻找:

      $ awk '/some_pattern/ { gsub(/:.*/,"",$3); print $3 }' file |sort |uniq -c
      

      这会搜索您想要的模式(有点像grep),然后替换第三个元素(时间)的第一个冒号之后的所有内容,并打印剩余的内容(小时)。其余的如上所述。

      样本输出(上述任一变体):

       12 07
       34 08
       30 09
       51 10
      536 11
      346 12
      123 13
      

      这表明我在上午 7 点的查询中有 12 个匹配项,而我直到上午 11 点才真正开始使用这个系统。

      【讨论】:

      • /some_pattern/ 不是必需的;可以省略。
      • @Swiss 你是对的。我只是想模仿原始帖子的逻辑。没有正则表达式肯定会更快,但不清楚是否还有更多内容需要过滤。
      【解决方案3】:

      grep "^[ 0-9][0]9...

      除非我误解了您的问题,否则我认为这就是您要寻找的内容。将空白作为选项添加到第一个集合中,并将其锚定到行首。

      【讨论】:

      • 如何在上面的 for 循环中使用它?这样我就可以按小时获得输出数字
      • 您不能在字符类中使用正则表达式速记。
      【解决方案4】:

      要匹配从 0 到 9 的小时为空格或零填充的时间戳:

      使用基本的正则表达式

      grep '^\([ 01][0-9]\|2[0-3]\):[0-5][0-9]:[0-5][0-9]' file
      

      或扩展正则表达式

      grep -E '^([ 01][0-9]|2[0-3])(:[0-5][0-9]){2}' file
      

      参考:https://www.gnu.org/software/gnulib/manual/html_node/Regular-expression-syntaxes.html

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-17
      • 1970-01-01
      • 2017-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多