使用 grep 和 awk 过滤日期

con*_*fin 3 grep awk shell-script

我在我的.bash_aliases文件中创建了下面的别名

alias auth="grep \"$(date|awk '{print $2,$3}')\" /var/log/auth.log |
            grep -E '(BREAK-IN|Invalid user|Failed|refused|su|Illegal)'"
Run Code Online (Sandbox Code Playgroud)

这应该是:

  • 检查今天的日期
  • grepauth.log今天的消息
  • 用于匹配特定字符串的警告消息的 grep 今日消息

但是,它仅在有 2 位数的日期时才有效,因为编号 <10 的天数前面没有零。

例如,我运行date并将结果通过管道传输到awk. date输出Sat Jan 1 04:56:10 GMT 2011然后 awk 捕获$2并将$3它们提供给 grep,如下所示

Jan 1
Run Code Online (Sandbox Code Playgroud)

但是,当有一位数的日期时,消息auth.log显示如下

Jan  1 00:44:57 linux su[21249]: pam_unix(su:session): session closed for user root
Run Code Online (Sandbox Code Playgroud)

因此,有两个空格以下Janauth.log,但只有一个空格之后Jan在我的grep命令

如何修改命令以允许额外空间?

cam*_*amh 7

date | awk ...您可以将格式说明符与 date 命令一起使用,而不是使用,以获取所需的格式。根据date(1)手册页,%b是缩写的月份名称,%e是月份中的第几天,空格填充,与%_d.

下面的 date 命令应该给你一个你想要的形式的字符串:

date "+%b %e"
Run Code Online (Sandbox Code Playgroud)

您还可以将其他字符放入格式说明符中,因此如果您使用:

date "+^%b %e"
Run Code Online (Sandbox Code Playgroud)

你会得到一个仅在行首匹配日期的 grep 模式。这将防止在日志的消息部分中有日期的任何错误匹配。

正如 Steven D 所指出的,您也可以通过一次调用来做到这一点grep

auth()
{
    grep -E "$(date '+^%b %e')"'.*(BREAK-IN|Invalid|user|Failed|refused|su|Illegal)' /var/log/auth.log
}
Run Code Online (Sandbox Code Playgroud)

我根据与引用相关的评论中提到的问题进行了一些更改。我的引用规则是在将单独的单词分组为单个单词时使用单引号并防止元字符的 shell 扩展,并且仅当您想在多单词字符串中扩展时才使用双引号。

原来的答案有date双引号中的格式字符串,根据我上面的规则,这是错误的。我现在已经改变了。编辑将 grep 字符串放入双引号中。我把它放回单引号中,因为 shell 元字符和 grep 正则表达式 (RE) 元字符之间经常存在重叠,以至于您几乎总是希望将 RE 单引号到 grep。当前字符串可能不需要单引号,但如果这个 shell 函数随着时间的推移而发展,它可能会随着未来的变化而中断。

由于问题是询问将命令放入别名中,因此此答案中未显示额外的引用级别。使用 shell 函数而不是别名会更简单,因此您不需要处理这种额外的引用级别。嵌套引用很快就会变得混乱,因此您应该做任何可以避免它的事情。

我已经将此作为 shell 函数进行了测试,使用 Gilles 建议对日期进行模糊处理,并且它“对我有用”。

  • @camh:在 Linux 下,你可以使用 `date -d '10 days ago' '+^%b %e'` 来测试。 (2认同)