使用 AWK 为日志添加前缀
Add a prefix to logs with AWK
我需要用于日志分析的脚本有问题;让我解释一下这个问题:
我有一个 gzip 文件,如:
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
我需要一个脚本来读取 gzipped 日志文件,它能够在 stdout 上输出修改后的日志行,如下所示:
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 '{[=13=]="5555 "[=13=]}' "
这不完全是我需要的(前缀是静态的,不是用文件名中的正则表达式捕获的)但即使使用这个简化版本,我也会收到错误消息:
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
正如您从上面的输出中看到的那样,[=17=]
不再是通过管道传递给 awk 的整行,而是一个 奇怪的 -bash
。
我需要使用 xargs,因为 gzip 文件列表是从另一个工具(即实例化的 inotifywait
侦听通过 ftp 写入文件的目录的命令行).
我缺少什么?你有什么建议可以指引我正确的方向吗?
此致,
S.
为了遵循@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=""
PATTERN="\.gz$"
script=$(cat <<'EOF'
awk -v filename="$file" 'BEGIN{split(filename,array,"_")}{[=15=]=array[1] OFS [=15=]} 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脚本感觉很迷茫
此致,
S.
编辑: 此外,如果您正在处理多个 .gz
文件并希望将它们的内容与它们一起打印文件名(第一列 _ 分隔)然后以下可能对您有所帮助。
for file in *.gz; do
awk -v filename="$file" 'BEGIN{split(filename,array,"_")}{[=10=]=array[1] OFS [=10=]} 1' <(gzip -dc "$file")
done
我还没有测试过你的代码(也不能完全理解),所以试着在这里提供一种方法,如果你的代码可以将文件名传递给 awk
那么它会非常简单附加文件的第一个数字,如下所示(仅作为示例)。
awk 'FNR==1{split(FILENAME,array,"_")} {[=11=]=array[1] OFS [=11=]} 1' 5555_prova.log_file
所以在这里我将 FILENAME
开箱即用变量用于 awk
(仅在文件的第一行),然后将其拆分为名为 array 的数组,然后将其添加到每一行文件。
同时将 "gunzip -c STR
以结尾 "
包装起来,在将其输出也传递给 awk
之前似乎丢失了。
从不,永远 使用 xargs -I
将字符串替换为 sh -c
(或 bash -c
或解释该字符串的任何其他上下文作为代码)。这允许恶意文件名 运行 任意命令——想想如果有人 运行 s touch $'$(rm -rf ~)\'$(rm -rf ~)\'.gz'
并将该文件放入您的日志中会发生什么。
相反,让 xargs
在脚本文本 之后附加参数 ,并编写脚本以迭代/读取这些参数作为数据,而不是将它们替换为代码。
为了展示如何安全地使用 xargs
(嗯,安全地 if 我们假设您已经过滤掉了带有文字换行符的文件名):
# 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 '{[=10=]="5555 "[=10=]}'; done
EOF
)
# if you **did** want to escape them by hand, it would look like this:
# script='for arg; do gunzip -c <"$arg" | awk '"'"'{[=10=]="5555 "[=10=]}'"'"'; done'
echo "./5555_prova.log.gz" | xargs -d $'\n' sh -c "$script" _
为了更安全地使用所有可能的 文件名,您应该改用:
printf '%s[=11=]' "./5555_prova.log.gz" | xargs -0 sh -c "$script" _
注意使用 NUL 分隔的输入(使用 printf '%s[=18=]'
创建)和 xargs -0
来使用它。
我需要用于日志分析的脚本有问题;让我解释一下这个问题:
我有一个 gzip 文件,如:
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
我需要一个脚本来读取 gzipped 日志文件,它能够在 stdout 上输出修改后的日志行,如下所示:
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 '{[=13=]="5555 "[=13=]}' "
这不完全是我需要的(前缀是静态的,不是用文件名中的正则表达式捕获的)但即使使用这个简化版本,我也会收到错误消息:
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
正如您从上面的输出中看到的那样,[=17=]
不再是通过管道传递给 awk 的整行,而是一个 奇怪的 -bash
。
我需要使用 xargs,因为 gzip 文件列表是从另一个工具(即实例化的 inotifywait
侦听通过 ftp 写入文件的目录的命令行).
我缺少什么?你有什么建议可以指引我正确的方向吗?
此致, S.
为了遵循@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=""
PATTERN="\.gz$"
script=$(cat <<'EOF'
awk -v filename="$file" 'BEGIN{split(filename,array,"_")}{[=15=]=array[1] OFS [=15=]} 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脚本感觉很迷茫
此致, S.
编辑: 此外,如果您正在处理多个 .gz
文件并希望将它们的内容与它们一起打印文件名(第一列 _ 分隔)然后以下可能对您有所帮助。
for file in *.gz; do
awk -v filename="$file" 'BEGIN{split(filename,array,"_")}{[=10=]=array[1] OFS [=10=]} 1' <(gzip -dc "$file")
done
我还没有测试过你的代码(也不能完全理解),所以试着在这里提供一种方法,如果你的代码可以将文件名传递给 awk
那么它会非常简单附加文件的第一个数字,如下所示(仅作为示例)。
awk 'FNR==1{split(FILENAME,array,"_")} {[=11=]=array[1] OFS [=11=]} 1' 5555_prova.log_file
所以在这里我将 FILENAME
开箱即用变量用于 awk
(仅在文件的第一行),然后将其拆分为名为 array 的数组,然后将其添加到每一行文件。
同时将 "gunzip -c STR
以结尾 "
包装起来,在将其输出也传递给 awk
之前似乎丢失了。
从不,永远 使用 xargs -I
将字符串替换为 sh -c
(或 bash -c
或解释该字符串的任何其他上下文作为代码)。这允许恶意文件名 运行 任意命令——想想如果有人 运行 s touch $'$(rm -rf ~)\'$(rm -rf ~)\'.gz'
并将该文件放入您的日志中会发生什么。
相反,让 xargs
在脚本文本 之后附加参数 ,并编写脚本以迭代/读取这些参数作为数据,而不是将它们替换为代码。
为了展示如何安全地使用 xargs
(嗯,安全地 if 我们假设您已经过滤掉了带有文字换行符的文件名):
# 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 '{[=10=]="5555 "[=10=]}'; done
EOF
)
# if you **did** want to escape them by hand, it would look like this:
# script='for arg; do gunzip -c <"$arg" | awk '"'"'{[=10=]="5555 "[=10=]}'"'"'; done'
echo "./5555_prova.log.gz" | xargs -d $'\n' sh -c "$script" _
为了更安全地使用所有可能的 文件名,您应该改用:
printf '%s[=11=]' "./5555_prova.log.gz" | xargs -0 sh -c "$script" _
注意使用 NUL 分隔的输入(使用 printf '%s[=18=]'
创建)和 xargs -0
来使用它。