Bash脚本:在sed中使用变量/参数

时间:2013-05-15 11:51:57

标签: bash sed

我正在尝试编写一个小的bash脚本,您可以在其中指定分钟数,它将显示最近X分钟的日志文件行。 要获得这些行,我使用的是sed

sed -n '/time/,/time/p' LOGFILE

在CLI上,这完全有效,但在我的脚本中却没有。

# Get date
now=$(date "+%Y-%m-%d %T")

# Get date minus X number of minutes -- $1 first argument, minutes
then=$(date -d "-$1 minutes" +"%Y-%m-%d %T")

# Filter logs -- $2 second argument, filename
sed -n '/'$then'/,/'$now'/p' $2

我尝试了不同的方法,似乎没有一种方法可以工作:

result=$(sed -n '/"$then"/,/"$now"/p' $2)
sed -n "/'$then'/,/'$now'/p" "$2"
sed -n "/$then/,/$now/p" $2
sed -n "/$then/,/$now/p" "$2

任何sugesstions? 我在Debian 5上,echo $SHELL/bin/sh

编辑:脚本不产生输出,因此不会显示错误。 在日志文件中,每个条目都以此2013-05-15 14:21:42,794

之类的日期开头

2 个答案:

答案 0 :(得分:1)

不要用嵌套引号让自己头疼。使用-v选项和awk将shell变量的值传递给脚本:

#!/bin/bash

# Get date
now=$(date "+%Y-%m-%d %T")

# Get date minus X number of minutes -- $1 first argument, minutes
delta=$(date -d "-$1 minutes" +"%Y-%m-%d %T")

# Filter logs -- $2 second argument, filename
awk -v n="$now" -v d="$delta" '$0~n,$0~d' $2

也不要使用shell内置函数的变量名,即then

答案 1 :(得分:1)

我认为主要问题是您尝试通过字符串匹配执行算术比较。 sed -n '/23/,/27/p'为您提供包含23的第一行与包含27的下一行(然后再从包含23的下一行到下一行)之间的行包含27,等等。它为你提供包含23到27之间数字的所有行。如果输入看起来像

19
22
24
26
27
30

它不输出任何内容(因为没有23)。使用字符串匹配的awk解决方案具有相同的问题。因此,除非您的then日期字符串逐字地出现在日志文件中,否则您的方法将失败。您必须将日期字符串转换为数字(删除-<space>:),然后使用算术比较检查结果数字是否在正确的范围内,而不是字符串匹配。这超出了sed的能力; awk和perl可以很容易地完成它。这是一个perl解决方案:

#!/bin/bash

NOW=$(date "+%Y%m%d%H%M%S")
THEN=$(date -d "-$1 minutes" "+%Y%m%d%H%M%S")

perl -wne '
  if (m/^(....)-(..)-(..) (..):(..):(..)/) {
    $date = "$1$2$3$4$5$6";
    if ($date >= '"$THEN"' && $date <= '"$NOW"') {
      print;
    }
  }' "$2"