Bash:将多行函数结果相互格式化

时间:2015-07-20 14:39:27

标签: bash logging printf bash-function

我有三个功能可以消化我服务器上的access.log文件。

hitsbyip() {
        cat $ACCESSLOG | awk '{ print $1 }' | uniq -c | sort -nk1 | uniq
}
hitsbyhour() {
        cat $ACCESSLOG | cut -d[ -f2 | cut -d] -f1 | awk -F: '{print $2":00"}' | sort -n | uniq -c
}
hitsbymin() {
        hr=$1
        grep "2015:${hr}" $ACCESSLOG | cut -d[ -f2 | cut -d] -f1 | awk -F: '{print $2":"$3}' | sort -nk1 -nk2 | uniq -c
}

当他们自己使用时,它们都可以正常工作。所有三个输出2个小数据柱。

现在我想创建另一个名为report的函数,它只使用printf及其格式化可能性,用标题打印3列数据,每一行都是我的三个第一个函数的结果。这样的事情:

report() {
       printf "%-30b %-30b %-30b\n" `hitsbyip` `hitsbyhour` `hitsbymin 10`
}

问题是格式不是我想要的;它可以横向打印出列而不是并排打印出来。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:3)

使用paste将三个命令的输出合并为一个流然后,您可以逐行操作以格式化这些输出。

while IFS=$'\t' read -r by_ip by_hour by_min; do
  printf '%-30b %-30b %-30b\n' "$by_ip" "$by_hour" "$by_min"
done < <(paste <(hitsbyip) <(hitsbyhour) <(hitsbymin 10))

要注意的要素:

  • <()语法为process substitution;它会生成一个文件名(通常在具有此类支持的平台上为/dev/fd/##形式),在读取时,将生成给定命令的输出。
  • paste获取一系列文件名,并将每个文件的输出与其他文件同时放在一起。
  • 在阅读时设置IFS=$'\t'可确保我们将内容读取为制表符分隔值(格式paste创建)。有关使用read
  • 的详细信息,请参阅BashFAQ #1
  • printf的参数上加上引号可确保我们将read汇编的每个值作为单个值传递给printf,而不是让它们受到字符串拆分和glob的约束 - 扩展为未加引号的值。