2

我正在尝试打印 sar 输出,不包括带有主机名和日期的标头。以下命令也不能排除标题行和输出字段分隔符:

sar -u|head -5|awk -F '
  BEGIN { hname="'"`hostname -s`"'"; hdt="'"`date +"%d-%b-%Y" `"'" ; OFS="," ;}
  { $1 ~ /[0-9]/ && $4 ~ /[0-9]/ }
  { printf( "h=%-15s d=%11s 1=%8s 2=%2s 3=%-3s 4=%6.2f 5=%6.2f 6=%6.2f 7=%6.2f 8=%6.2f 9=%6.2f\n", hname, hdt, $1, $2, $3, $4, $5, $6, $7, $8, $9 );}'

但是当使用相同的搜索 exp 时效果很好!

4

2 回答 2

1

试试下面的代码:

sar -u|head -5|awk '
  BEGIN { hname="'"`hostname -s`"'"; hdt="'"`date +"%d-%b-%Y" `"'" ; OFS="," ;} 
  $1 ~ /[0-9]/ && $4 ~ /[0-9]/
  { printf( "h=%-15s d=%11s 1=%8s 2=%2s 3=%-3s 4=%6.2f 5=%6.2f 6=%6.2f 7=%6.2f 8=%6.2f 9=%6.2f\n", hname, hdt, $1, $2, $3, $4, $5, $6, $7, $8, $9 );}'

请注意,这是未经测试的,因为我没有sar程序。如果您粘贴该程序的一些示例输出,我可以测试代码并相应地更新我的答案。

这与您的代码尽可能接近,如果我没有错过任何其他内容,它应该可以工作。您使用的-F选项没有执行任何操作,因为您没有指定新的字段分隔符( FS)。请注意,我删除了“搜索”语句{...}周围的大括号(大括号) 。$1 ~ /[0-9]/ && $4 ~ /[0-9]/

awk程序由模式和相关操作组成,这些操作针对与模式匹配的那些记录(没有其他选项,每一行被视为一条记录)执行。行动_模式之后用大括号括起来。

因此,您的代码具有三个操作:与特殊BEGIN 模式相关联的初始化,因此在读取任何输入之前执行一次,以及对所有记录(即行)执行的两个操作,因为它们与任何模式无关:第一个评估您的搜索表达式和第二个打印格式化记录。但是请注意,这两个操作没有关联,无论您的搜索表达式评估为真还是假,都会执行打印操作。

要了解您的代码有什么问题,您可以运行以下详细版本:

sar -u|head -5|awk '
  BEGIN { hname="'"`hostname -s`"'"; hdt="'"`date +"%d-%b-%Y" `"'" ; OFS="," ;} 
  {print "search returned "($1 ~ /[0-9]/ && $4 ~ /[0-9]/?"true.":"false.")}
  { printf( "h=%-15s d=%11s 1=%8s 2=%2s 3=%-3s 4=%6.2f 5=%6.2f 6=%6.2f 7=%6.2f 8=%6.2f 9=%6.2f\n", hname, hdt, $1, $2, $3, $4, $5, $6, $7, $8, $9 );}'

这扩展了您的第一个操作以打印搜索表达式的结果,您将看到第二个(即printf操作是独立于该结果执行的。

通过删除搜索表达式周围的大括号,您可以使其成为与下一个操作相关联的模式,即那个。这种方式只对那些与您的搜索模式匹配的记录(即行)执行。printfprintf

进一步注意,如果您按照@jaypal singh的建议将外部命令的输出存储在变量中,您的代码将变得更具可读性,以下是通过使用选项初始化变量来实现的:awk-v

sar -u|head -5|awk \
                -v hname="`hostname -s`" \
                -v hdt="`date +"%d-%b-%Y"`" \
                -v OFS="," \
               '
                $1 ~ /[0-9]/ && $4 ~ /[0-9]/{
                 printf( "h=%-15s d=%11s 1=%8s 2=%2s 3=%-3s 4=%6.2f 5=%6.2f 6=%6.2f 7=%6.2f 8=%6.2f 9=%6.2f\n", hname, hdt, $1, $2, $3, $4, $5, $6, $7, $8, $9 )
                }
               '

附录:

正如@jaypal singh所指出的,输出字段分隔符( OFS) 不会影响prinft,因此您可能希望在语句中使用逗号 ( ,) 而不是空格 ( )而不是定义:printfOFS

sar -u|awk \
        -v hname="`hostname -s`" \
        -v hdt="`date +"%d-%b-%Y"`" \
       '
        $1 ~ /[0-9]/ && $4 ~ /[0-9]/{
         printf( "h=%-15s,d=%11s,1=%8s,2=%2s,3=%-3s,4=%6.2f,5=%6.2f,6=%6.2f,7=%6.2f,8=%6.2f,9=%6.2f\n", hname, hdt, $1, $2, $3, $4, $5, $6, $7, $8, $9 )
        }
       '

请注意,这一次我也head从管道中删除了,因为您在评论中说这只是出于测试原因而引入,如果它不使用记录号( NR) 会更好,正如@jaypal singh所建议的那样。

于 2013-09-09T05:58:29.760 回答
0

这是您需要做的:

$ hname=$(hostname -s)
$ hdt=$(date +"%d-%b-%Y")
$ $ sar -u | awk '$1~/[0-9]/&&$4~/[0-9]/&&NR<=5{print host,dat,$1,$2,$3,$4,$5,$6,$7,$8,$9}' OFS="," host="$hname" dat="$hdt"

一些指示:

  • 不需要head,你可以使用NR变量来控制行数
  • 要在其中使用 bash 命令,awk您需要使用system(),或者您可以将 bash 命令存储在变量中并awk像我们上面所做的那样调用它们。
  • 输出分隔符变量 OFS并且对语句ORS没有影响printf
于 2013-06-24T13:29:58.370 回答