为AWK日志添加前缀

时间:2018-06-19 16:25:17

标签: bash awk xargs

我遇到了需要用于日志分析的脚本问题;让我解释一下这个问题:

我有一个压缩文件,如:

5555_prova.log.gz

在文件内部有几行这样的日志:

2018-06-12    03:34:31    95.245.15.135    GET    /hls.playready.vod.mediasetpremium/farmunica/2018/06/218742_163f10da04c7d2/hlsrc/w12/21.ts

我需要一个脚本来读取压缩后的日志文件,该文件能够在标准输出上输出如下所示的修改后的日志行:

5555 2018-06-12    03:34:31    95.245.15.135    GET    /hls.playready.vod.mediasetpremium/farmunica/2018/06/218742_163f10da04c7d2/hlsrc/w12/21.ts

如您所见,日志行现在以从gzip文件名读取的数字开头。 我需要此新行来填充logstash数据处理链。

我尝试过使用如下脚本:

 echo "./5555_prova.log.gz" | xargs -ISTR -t -r  sh -c "gunzip -c STR | awk '{$0="5555 "$0}' "

这并不是我真正需要的(前缀是静态的,并且没有使用文件名中的正则表达式捕获),但是即使使用此简化版本,我也会收到错误消息:

sh -c gunzip -c ./5555_prova.log.gz | awk '{-bash=5555 -bash}'
-bash}' : -c: line 0: unexpected EOF while looking for matching `''
-bash}' : -c: line 1: syntax error: unexpected end of file

从上面的输出中可以看到,$0不再是通过管道传递到awk的整行,而是 strange -bash

我需要使用xargs,因为从另一个工具(例如,实例化的inotifywait侦听通过ftp写入文件的目录)将命令行压缩的文件压缩到gzip文件列表中。 我缺少什么?您有什么建议可以指引我正确的方向吗?

关于,


尝试遵循@Charles Duffy的建议,我编写了以下代码:

#/bin/bash

#
# Usage: sendToLogstash.sh [pattern]
#
# Executes a command whenever files matching the pattern are closed in write
# mode or moved to. "{}" in the command is replaced with the matching filename (via xargs).
# Requires inotifywait from inotify-tools.
#
# For example,
#
#    whenever.sh '/usr/local/myfiles/'
#
#


DIR="$1"
PATTERN="\.gz$"

script=$(cat <<'EOF'
awk -v filename="$file" 'BEGIN{split(filename,array,"_")}{$0=array[1] OFS $0} 1' < $(gunzip -dc "$DIR/$file")
EOF
)

inotifywait -q --format '%f' -m -r -e close_write -e moved_to "$DIR" \
      | grep --line-buffered $PATTERN | xargs -I{} -r sh -c "file={}; $script"

但是我得到了错误:

[root@ms-felogstash ~]# ./test.sh ./poppo
gzip: /1111_test.log.gz: No such file or directory
gzip: /1111_test.log.gz: No such file or directory
sh: $(gunzip -dc "$DIR/$file"): ambiguous redirect

感谢您的帮助,我对编写bash脚本感到非常迷茫。

关于,

2 个答案:

答案 0 :(得分:2)

EDIT: 另外,如果您要处理多个.gz文件,并希望将其内容和文件名一起打印(第一列_分隔)那么以下内容可能会对您有所帮助。

for file in *.gz; do
    awk -v filename="$file" 'BEGIN{split(filename,array,"_")}{$0=array[1] OFS $0} 1' <(gzip -dc "$file")
done


我还没有测试过您的代码(也无法完全理解),因此尝试给出一种类似的方式,以防您的代码可以将文件名传递给awk,那么添加文件的第一个数字如下(仅作为示例)。

awk 'FNR==1{split(FILENAME,array,"_")} {$0=array[1] OFS $0} 1' 5555_prova.log_file

所以在这里,我从FILENAME的框变量中取出awk(仅在文件的第一行),然后将其拆分为名为array的数组,然后将其添加到文件。

还用结尾"gunzip -c STR包装",在将其输出也传递给awk之前,它似乎也丢失了。

答案 1 :(得分:2)

从不,永远xargs -I与字符串替换为sh -c(或bash -c或将该字符串解释为代码的任何其他上下文)一起使用。这允许恶意文件名运行任意命令-考虑如果有人运行touch $'$(rm -rf ~)\'$(rm -rf ~)\'.gz'并将该文件保存到您的日志中会发生什么情况。

相反,让xargs在脚本文本后的 之后添加参数,然后编写脚本以将这些参数作为数据进行迭代/读取,而不是将其替换为代码。


要显示如何安全地使用xargs(好吧,如果,我们假设您已经过滤掉了带文字换行符的文件名):

# This way you don't need to escape the quotes in your script by hand
script=$(cat <<'EOF'
for arg; do gunzip -c <"$arg" | awk '{$0="5555 "$0}'; done
EOF
)

# if you **did** want to escape them by hand, it would look like this:
#   script='for arg; do gunzip -c <"$arg" | awk '"'"'{$0="5555 "$0}'"'"'; done'

echo "./5555_prova.log.gz" | xargs -d $'\n' sh -c "$script" _

为了更安全地使用所有可能的文件名,您应该使用:

printf '%s\0' "./5555_prova.log.gz" | xargs -0 sh -c "$script" _

请注意使用NUL分隔的输入(由printf '%s\0'创建)和xargs -0来使用它。