【问题标题】:Using sed/awk and regex to process logs使用 sed/awk 和正则表达式处理日志
【发布时间】:2011-10-23 19:04:30
【问题描述】:

我有 1000 多个由非常冗长的 PHP 脚本生成的日志文件。大体结构如下

###Unknown no of lines, which I want to ignore###
=================================================
$insert_vars['cdr_pkey']=17568
$id<TAB>$g1<TAB>$i1<tab>rating1<TAB>$g2<TAB>$i2<tab>rating2 #<TAB>more $gX,$iX,$ratingX
#numerical values of $id $g1 $i1 etc. separated by tab
#numerical values of ---""---
#I do not know how many lines will be there (unique column is $id)
=================================================
###Unknown no of lines, which I want to ignore###

我必须处理这些日志文件并创建一个 excel 表(我正在考虑 csv 格式)并将数据报告回来。我真的不擅长 excel,但我想输出类似的东西:

cdr_pkey<TAB>id<TAB>g1<TAB>i1<TAB>rating1<TAB>g2<TAB>rating2 #and so on
17568<TAB>1349<TAB>0.0004532<TAB>0.01320<TAB>2.014E-4<TAB>...#rest of numerical values
17568<TAB>1364<TAB>...#values for id=1364
17568<TAB>1321<TAB>...#values for id=1321
...
17569<TAB>1048<TAB>...#values for id=1048
17569<TAB>1426<TAB>...#values for id=1426
...
...

所以我的 cdr_pkey 是工作表中的唯一列,对于每个 $cdr_pkey,我有多个 $ids,每个都有自己的一组 $g1,$i1,$rating1...
测试这种格式后,可以被excel读取。现在我只想将它扩展到所有这 1000 个文件。
我只是不确定如何进一步进行。下一步是什么?

【问题讨论】:

  • 日志文件结构是否一致(即所有日志文件包含相同顺序的相同列)?另外,您想要一个输出文件还是每个输入一个?
  • 是的,日志文件结构是一致的。我想要单个输出文件。每个输入文件都有唯一的$insert_vars['cdr_pkey'],我想将所有文件与初始列合并为cdr_pkey@Tomalak:谢谢

标签: regex sed awk logging


【解决方案1】:

以下 bash 脚本执行的操作可能与您想要的有关。当你说&lt;TAB&gt; 时,它是由你的意思参数化的。我假设您的意思是 ascii 制表符,但如果您的日志非常冗长以至于它们拼写出 &lt;TAB&gt;,您将需要相应地修改变量 $WHAT_DID_YOU_MEAN_BY_TAB。请注意,这个脚本很少做 The Right Thing™;它将整个文件读入一个字符串变量,这甚至可能取决于您的日志文件有多大。从好的方面来说,如果您认为这样更好,可以轻松修改脚本以进行两次传递。

#!/bin/bash

WHAT_DID_YOU_MEAN_BY_TAB='\t'

if [[ $# -ne 1 ]] ; then echo "Requires one argument: the file to process" ; exit 1 ; fi

FILENAME="$1"

RELEVANT=$(sed -n '/^==*$/,/^==*$/p' "$FILENAME" | sed '1d' | head -n '-1')
CDR_PKEY=$(echo "$RELEVANT" | \
    grep '$insert_vars\['"'cdr_pkey'\]" | \
    sed 's/.*=\(.*\)/\1/')
echo "$RELEVANT" | sed '1,2d' | \
    sed "s/.*/${CDR_PKEY}$WHAT_DID_YOU_MEAN_BY_TAB\0/"

以下find 命令是一个示例用法,但您的情况将取决于您的日志的组织方式。

find . LOG_PATTERN -exec THIS_SCRIPT '{}' \;

最后,我忽略了将 CSV 标头放在输出上的问题。这很容易在带外完成。

(编辑:更新脚本以反映 cmets 中的讨论。)

【讨论】:

  • 太棒了!我只需要输入一次$id\t$g1\t...所以我输入了。我根据您的脚本在下面添加了自己的答案。非常感谢!
  • 如果我正确理解您的编辑,您也可以将RELEVANT 行从...sed '1d'... 更改为...sed 1,2d...
  • 如果我这样做(并删除grep -v 'id')我没有得到第一个'cdr_pkey'值。它只是从具有“id”值的第二列开始
  • 哎呀,我的意思是你有grep -v 命令的最后一行。将 那个 sed...'1d'... 更改为 ...'1,2d'...
【解决方案2】:

编辑:James 告诉我,将最后一个 echo 中的 sed... 1d ... 更改为 ... 1,2 ... 并删除 grep -v 'id' 应该可以解决问题。
确认它有效。所以下面改一下。再次感谢 James Wilcox。


基于@James 脚本,这就是我想出的。我刚刚将最终的回声传送到grep -v 'id'
再次感谢詹姆斯威尔科克斯
WHAT_DID_YOU_MEAN_BY_TAB='\t'

if [[ $# -lt 1 ]] ; then echo "Requires at least one argument: the files to process" ; exit 1 ; fi

echo -e "key\tid\tg1\ti1\td1\tc1\tr1\tg2\ti2\td2\tc2\tr2\tg3\ti3\td3\tc3\tr3"

for i in "$@"
do
    FILENAME="$i"
    RELEVANT=$(sed -n '/^==*$/,/^==*$/p' "$FILENAME" | sed '1d' | head -n '-1')
    CDR_PKEY=$(echo "$RELEVANT" | \
        grep '$insert_vars\['"'cdr_pkey'\]" | \
        sed 's/.*=\(.*\)/\1/')
    echo "$RELEVANT" | sed '1, 2d' | \
        sed "s/.*/${CDR_PKEY}$WHAT_DID_YOU_MEAN_BY_TAB\0/"
    #the one with grep looked like :-
    #echo "$RELEVANT" | sed '1d' | \
        #sed "s/.*/${CDR_PKEY}$WHAT_DID_YOU_MEAN_BY_TAB\0/" | grep -v 'id'
done

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 1970-01-01
    相关资源
    最近更新 更多