【问题标题】:Escaping slashes in bash (awk)在 bash (awk) 中转义斜杠
【发布时间】:2015-11-17 15:53:37
【问题描述】:

尝试从 Apache 日志文件中获取一行和所有后续行,我希望简化以下内容:

# Convert epoch to format used in log file
gtime=$(date -d @$etime +"%d/%b/%Y:%T")  # "17/Nov/2015:16:36:45"
# Escape the slashes
g_tim=$(echo $gtime | sed 's/\//\\\//g') # "17\/Nov\/2015:16:36:45"
# Grab 
lines=$(awk '/$g_tim/,0' access.log)

如果我不必为此使用两个变量会更好,而且我确信我会犯其他各种罪过。

日志文件示例:

djerk.nl:80 79.134.133.108 - - [17/Nov/2015:18:51:52 +0100] "GET /wordpress/2015/null HTTP/1.1" 103 16544 "http://www.djerk.nl/wordpress/2015/cisco-lacp-config-for-aruba-ap" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36"
djerk.nl:80 92.27.44.117 - - [17/Nov/2015:18:52:28 +0100] "GET /djerk_nl.pac HTTP/1.1" 403 1147 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36"

【问题讨论】:

  • 昨晚一定太晚了,我没注意到编辑按钮...

标签: bash shell date awk sed


【解决方案1】:

您想打印从匹配17/Nov/2015:16:36:45 的行到最后的所有内容。那么,为什么不使用这种语法呢?

awk '$0 ~ /pattern/ {f=1} f' file

这会在第一次看到模式时设置一个标志。从那一刻起,f 条件为 True,因此所有行都打印到文件末尾。

在你的情况下,

awk -v date="$(date -d @$etime +"%d/%b/%Y:%T")" '$0~date {f=1}f' file

【讨论】:

  • 好一个 +1 是的,我认为这是 OP 需要的
  • 完美,谢谢。 Pitty 我发现我的工作流程有问题,但这完全是另一个问题。我认为在提取最后 5 分钟的记录行时,跟踪行号而不是每行的日期会更容易。
  • 这对我来说可能会进一步简化事情:awk -v date="$(date --date='5 minutes ago' +"%d/%b/%Y:%T")" '$0~date {f=1}f' other_vhosts_access.log。如果不是因为从命令行读取日志文件失败的事实,我想当 Apache 打开文件时。我也很好奇如果 cron 不能每 300 秒准确地执行一次我的代码,我是否会丢失行或重复...
  • @dmgeurts 有趣的命令。您可能需要添加 -5 秒或其他时间来补偿 crontab 上可能出现的问题。
  • @dmgeurts 我的错,我没有正确解释。我想说的是,如果您担心会浪费一些时间,您还可以将date 变量设置为一些额外的秒数,例如(我不知道这是否正确)date --date='5 minutes ago + 5 sec' .
【解决方案2】:

从您的 cmets 看来,您并不是真的想要 grab a line and all following lines,而是想要打印从给定时间戳开始或之后的所有行。那将是:

$ cat tst.awk
BEGIN { FS="[][ /:]+"; mths="JanFebMarAprMayJunJulAugSepOctNovDec" }
f { print; next }
{ logTime = sprintf("%04d%02d%02d%02d%02d%02d",$8,(match(mths,$7)+2)/3,$6,$9,$10,$11) }
logTime >= tgtTime { f=1 }

$ awk -v tgtTime="$(date -d @"$etime" +"%Y%m%d%H%M%S")" -f tst.awk file

请注意,我更改了 date 时间规范参数以生成新的时间戳格式以进行比较。

【讨论】:

  • 你说得对。我错误地认为一天中没有一秒钟没有针对它的 Apache 日志条目。事后看来,我有多么错误,这是一个非常糟糕的假设。让我想知道什么更快。在每一行中搜索一个字符串直到匹配? (while != result; etime +1)
  • 刚刚发现日志文件也包含IPv6地址。这些会分裂并造成严重破坏......我将不得不清理我解析的数据,但是如何......wantedLines=$( awk -v tgtTime="$etime" 'BEGIN { FS="[][ /:]+"; mths="JanFebMarAprMayJunJulAugSepOctNovDec" } f { print; next } { logTime = sprintf("%04d%02d%02d%02d%02d%02d",$8,(match(mths,$7)+2)/3,$6,$9,$10,$11) } logTime >= tgtTime { f=1 }' $log_file )
  • 您在评论错误的答案,您应该与您选择正确答案的作者讨论您的问题/需求。
  • 更改了选择的答案,因为您的答案比较了时间戳,而我之前选择的答案寻找完全匹配,这是我在选择它作为最佳答案后发现的。也许我需要等待更长的时间才能选择下一次最佳答案?
  • @dmgeurts 好吧,您可能必须从一开始就明确自己的想法,因为每次您添加新要求时我们都无法不断更改答案:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-07
  • 2017-10-17
  • 1970-01-01
  • 2015-09-22
  • 1970-01-01
相关资源
最近更新 更多