使用 bash 实时读取日志

使用 bash 实时读取日志

我在系统日志中有这个:

Feb 27 02:53:51 Latitude-E6430 rsyslogd: action up   7
Feb 27 02:53:51 Latitude-E6430 rsyslogd: action down B
Feb 27 02:53:51 Latitude-E6430 rsyslogd: action up   U
....etc

我想编写一个脚本来全天候监控日志作为服务,但我不知道如何执行该条件。

1-当您逐行读取时,将其存储在变量中。

2 -读取变量如果它在该行中找到单词 [rsyslogd] 和 [7],则显示 [echo "Found" ]

这将是一个循环,逐行读取文件,寻找单词模式。

示例脚本

path_full_log="/home/full.log"


function reader_time_real(){

    while read full_log; do
        chek7=$(cat $full_log | grep "rsyslogdd" | grep 7 )
            if [[ $? = 0 ]]; then 
                echo "Found 7";

            fi

        chekB=$(cat $full_log | grep "rsyslogdd" | grep B )
            if [[ $? = 0 ]]; then 
                echo "Found B";

            fi
    done < $path_full_log
}

答案1

您的脚本不适合执行您想要的操作。它只读取文件一次,但读取完整。如果您循环执行此操作,您将不会只获得新的输出,这将是一场性能噩梦。

此外,你对 的使用毫无用处cat,你使用grep一个带有正则表达式模式的固定字符串,并将结果保存在你不再使用的变量中。此外,你不应该使用不带引号的文件名变量。


使用tail -f | grep --line-buffered

tail -fn0 "$path_full_log" \
| grep -F --line-buffered 'rsyslogdd' \
| grep -Eo --line-buffered '(7|B)' \
| while read line; do
      echo "Found $line"
  done

或者使用xargs

tail -fn0 "$path_full_log" \
| grep -F --line-buffered 'rsyslogdd' \
| grep -Eo --line-buffered '(7|B)' \
| xargs -I{} echo "Found {}"
  • tail -fn0当文件添加新行时,读取新行。
  • grep -F在该行中搜索固定字符串。
  • --line-buffered告诉grep在行进入时读取行,而不是等待输入流的结束(这是默认设置)。
  • grep -Eo搜索模式ERE ( -E)(7|B)并仅输出匹配的字符串 ( -o)。
  • while read line或者xargs -I{}获取该输出并在输出上运行您的命令(此处echo:)。

答案2

我编写了以下脚本,该脚本每秒更新一次,并突出显示任何新的日志条目。它还定义了应显示日志的区域(使用和变量logrowslogcols,因此它适用于固定大小的终端窗口(我在 tmux 中使用它)。

您可以修改此脚本以仅突出显示符合特定条件的行,如您所指出的。

#!/bin/bash

# Initial configuration variables
logrows=31
logcols=127

# Local function definition
printnew() {
  clear
  echo -e "\e[0;30;47m"
  hightail=$(tail -n "$logrows" /var/log/syslog | cut -b "1-$logcols")
  echo -ne "${hightail}\e[0m"
}

printdif() {
  (( newrows = logrows - logdiff ))
  clear
  normtail=$(tail -n "$logrows" /var/log/syslog | head -n "$newrows" | cut -b "1-$logcols")
  echo -n "$normtail"
  echo -e "\e[0;30;47m"
  hightail=$(tail -n "$logdiff" /var/log/syslog | cut -b "1-$logcols")
  echo -ne "${hightail}\e[0m"
}

printold() {
  clear
  normtail=$(tail -n "$logrows" /var/log/syslog | cut -b "1-$logcols")
  echo -n "$normtail"
}

# Loop every second
while true
do
  sleep 1 &

  # Read log sizes
  logsize=$(wc -l /var/log/syslog | cut -d ' ' -f1)
  (( logdiff = logsize - presize ))

  # If more than $logrows lines are new
  if (( logdiff > "$logrows" ))
  then
    printnew
    redraw=1
  # If less than $logrows lines but more than 0 lines are new
  elif (( logdiff > 0 ))
  then
    printdif
    redraw=1
  # If no lines are new
  else
    if [[ "$redraw" -eq 1 ]]
    then
      printold
      redraw=0
    fi
  fi

  presize="$logsize"
  wait # for sleep
done

编写脚本时考虑了三种场景:

  1. 的全部内容logrows都是新的 - 所有内容均已突出显示(printnew)。
  2. 日志中的某些行是新的 - 这些行已突出显示(printdif)。
  3. 没有新的日志行 — — 没有任何内容突出显示 ( printold)。

免责声明:代码可能可以优化,但我通常更关心我的代码是否可读,而不是尽可能地简洁。

相关内容