Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 使用AWK为日志添加前缀_Bash_Awk_Xargs - Fatal编程技术网

Bash 使用AWK为日志添加前缀

Bash 使用AWK为日志添加前缀,bash,awk,xargs,Bash,Awk,Xargs,我面临着一个需要用于日志分析的脚本问题;让我解释一下问题: 我有一个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 5555 2018-06-12 03:34:31

我面临着一个需要用于日志分析的脚本问题;让我解释一下问题:

我有一个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
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日志文件,该文件能够在标准输出上输出修改后的日志行,如下所示:

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的整条线,而是一个奇怪的bash

我需要使用xargs,因为gzip文件的列表是从另一个工具(即实例化的inotifywait)发送到命令行的,该工具监听通过ftp写入文件的目录。 我错过了什么?你有什么建议给我指出正确的方向吗

问候,, 美国

试图遵循@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"
谢谢你的帮助,我觉得写bash脚本很迷茫

问候,, S.

编辑:如果您正在处理多个.gz文件,并且希望打印其内容及其文件名,那么下面的第一列将对您有所帮助

for file in *.gz; do
    awk -v filename="$file" 'BEGIN{split(filename,array,"_")}{$0=array[1] OFS $0} 1' <(gzip -dc "$file")
done
所以在这里,我在文件的第一行中为awkonly取出文件名变量,然后将其拆分为名为array的数组,然后将其添加到文件的每一行中

另外,在将输出传递给awk之前,还要将gunzip-c STR这段代码用结尾进行包装。

编辑:另外,如果您处理多个.gz文件,并希望打印其内容及其文件名,则第一列(以空格分隔)可能会对您有所帮助

for file in *.gz; do
    awk -v filename="$file" 'BEGIN{split(filename,array,"_")}{$0=array[1] OFS $0} 1' <(gzip -dc "$file")
done
所以在这里,我在文件的第一行中为awkonly取出文件名变量,然后将其拆分为名为array的数组,然后将其添加到文件的每一行中

另外,在将gunzip-c STR的输出也传递给awk之前,也要用似乎丢失的结尾将其包装起来。

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

相反,让xargs在脚本文本后附加参数,并编写脚本以将这些参数作为数据进行迭代/读取,而不是将它们替换为代码

为了演示如何安全地使用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”和xargs-0创建的NUL分隔输入来使用它。

切勿将xargs-I与替换为sh-c或bash-c的字符串或该字符串被解释为代码的任何其他上下文一起使用。这允许恶意文件名运行任意命令—想想如果有人运行touch$'$rm-rf~\'$rm-rf~\'.gz'并将该文件输入日志,会发生什么情况

相反,让xargs在脚本文本后附加参数,并编写脚本以将这些参数作为数据进行迭代/读取,而不是将它们替换为代码

为了演示如何安全地使用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”和xargs-0创建的NUL分隔输入来使用它。

您有嵌套的引号,而bash不理解。它认为你的枪拉链。。。报价以'{$0=并且会感到困惑,因为您有一个单引号。您的内部单引号是文字,而不是语法,因此在内容传递给awk之前,它们不会阻止shell替换$0。当由bash而不是awk解释时,按照惯例/默认情况下,$0是当前脚本的名称;对于交互式解释器,该名称是-bash。你有嵌套的引号,而bash不明白。它认为你的gunzip…引号以'{$0=并且会感到困惑,因为您有一个单引号。您的内部单引号是文字,而不是语法,因此在内容传递给awk之前,它们不会阻止shell替换$0。当由bash而不是awk解释时,按照惯例/默认情况下,$0是当前脚本的名称;对于交互式解释器,该名称是-bash。我需要实际的错误来说明任何事情。如果它不完全符合注释,您可以将您的尝试的确切代码和错误发布到吗?抱歉,我正在写注释,消息未完成。我会将代码添加到我的消息中。您编辑的代码与我的建议明显相反,我从未建议过您r在任何情况下
将文件名替换为解析为代码的字符串。file={}正是这种替代。此外,当代码包含一些不太正确的实现时,也会是这样。还要注意,我们必须先导出dir,然后才能被bash-c或sh-c调用的子进程看到。如果它不完全适合于评论,你可以发布你尝试的确切代码和错误吗?对不起,我正在写评论,消息不完整。我会将代码添加到我的邮件中。您编辑的代码与我的建议明显相反,我建议您在任何情况下都不要将文件名替换为解析为代码的字符串。file={}正是这种替代。此外,当代码包含一些不太正确的实现时,也会是这样。还要注意,我们必须先导出dir,然后才能被bash-c或sh-c调用的子进程看到。