awk - 将sum发送到全局变量

时间:2014-07-25 16:37:33

标签: linux bash awk scope

我在bash脚本中有一行,用于计算特定页面的唯一IP请求总和。

grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print } END { print " ", sum, "total"}'

我试图将sum的值加到awk语句之外的变量中,这样我就可以将页面相互比较。到目前为止,我尝试过各种类似的组合:

unique_sum=0 grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print ; $unique_sum=sum} END { print " ", sum, "total"}' echo "${unique_sum}"

这导致" 0"的回声。我已尝试将__$unique_sum=sum__放入END,初始化变量(awk -v unique_sum=0 ...)的各种组合以及将变量赋值置于引用部分之外。

到目前为止,我的Google-fu失败可怕,因为大多数人只是将整个输出发送到变量。在此示例中,除了总数之外,还打印了许多行(每个IP一行)。没有办法捕获总和'变量,有没有办法捕获最后一行输出?

这可能是我在awk中尝试过的最复杂的事情之一,所以我对自己做过任何有用的事情的信心非常低。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

您无法在awk程序中分配shell变量。通常,没有子进程可以改变其父进程的环境。你必须让awk程序打印出计算出的值,然后shell可以获取该值并将其分配给变量:

output=$( grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}' | sort | uniq -c | awk '{sum += 1; print } END {print sum}' )
unique_sum=$( sed -n '$p' <<< "$output" )  # grab the last line of the output
sed '$d' <<< "$output"          # print the output except for the last line
echo "     $unique_sum total"

该管道可以简化很多:awk可以做grep可以做的事情,所以首先

grep $YESTERDAY $ACCESSLOG | grep "$1" | awk -F" - " '{print $1}'

是(更长,但只有一个过程)

awk -F" - " -v date="$YESTERDAY" -v patt="$1" '$0 ~ date && $0 ~ patt {print $1}' "$ACCESSLOG"

最后一个awk程序只计算了多少行,可以用wc -l

替换

所有在一起:

unique_output=$(
    awk -F" - " -v date="$YESTERDAY" -v patt="$1" '
        $0 ~ date && $0 ~ patt {print $1}
    ' "$ACCESSLOG" | sort | uniq -c
)
echo "$unique_output"
unique_sum=$( wc -l <<< "$unique_output" )
echo "     $unique_sum total"