Shell脚本 - 按列过滤文本文件&将不存在

时间:2015-10-19 02:32:01

标签: shell unix

我想根据用户的输入(例如:1218738496)根据第8列过滤一个充满日志文件的目录,并输出到文本文件。我有一个有效的解决方案,但我正在寻找一个更好的解决方案,提供更好的性能,因为总文件大小可能超过1GB +。

问题1: 某些行格式不一致。

问题2: 如果第8行与输入匹配,则它下面的行(不包含INSERT)也应该输出到文件。

示例数据

ACTION,INSTALLATION_ID,LOG_TIMESTAMP_SECONDS,LOG_TIMESTAMP_FRACTIONS,LOG_TIMESTAMP,THREAD_ID,SEQUENCE_NUMBER,LOG_LEVEL_TYPE
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1127192896,0,DEBUG3
0010: 69 6c 65 40 10 92 0f 0e 67 b9 72 aa 5d e1 03 63
]",,default,false
INSERT,SLT_TEST_1,2015/06/02 14:07:13.305 (Asia/Colombo),1127192896,1,DEBUG1
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,14,DEBUG3
<v s=""MONTHLY_PEAK_DWNLOAD""/>
</a><a n=""thresholdScheme""><o t=""PM_UsageMonitorConfigThreshold"">
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,15,DEBUG3
0010: 69 6c 65 40 10 92 0f 0e 67 b9 72 aa 5d e1 03 63
]",,default,false
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,17,DEBUG3

期望的输出

INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,14,DEBUG3
<v s=""MONTHLY_PEAK_DWNLOAD""/>
</a><a n=""thresholdScheme""><o t=""PM_UsageMonitorConfigThreshold"">
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,15,DEBUG3
0010: 69 6c 65 40 10 92 0f 0e 67 b9 72 aa 5d e1 03 63
]",,default,false
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,17,DEBUG3

我目前的工作脚本

for file in $(ls -rt $directory)
do
    echo "Reading file : " $file
     # || [[ -n "$line" ]] <-- prevent last line being ignored if doesn't end with newline
    while IFS= read -r line || [[ -n "$line" ]]
    do 
        # if line contains INSERT
        if [[ $line == *"INSERT"* ]]
        then
            # Break it to access the thread ID
            breakdown=(${line//,/ })
            threadID=${breakdown[4]}

            if [[ $threadID == "$inputThreadID" ]]
            then
                seqID=${breakdown[5]}
                echo $line >> ./output_unsorted.txt
            fi
        else
            # The "too long lines" check if they belong to the ID log we want
            if [ "$threadID" == "$inputThreadID" ] && [[ $line != *"ACTION,INSTALLATION_ID"* ]]
            then
                if [ "$lastSeqID" != "$seqID" ]
                then
                    echo $line >> ./output_unsorted.txt
                else
                    echo $line >> ./output_unsorted.txt
                fi
            fi
        fi
    done < "$directory/$file"
done

1 个答案:

答案 0 :(得分:2)

使用awk

这会产生您要求的输出:

$ awk -F, '/INSERT/{f=0} $4==1218738496{f=1} f' file
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,14,DEBUG3
<v s=""MONTHLY_PEAK_DWNLOAD""/>
</a><a n=""thresholdScheme""><o t=""PM_UsageMonitorConfigThreshold"">
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,15,DEBUG3
0010: 69 6c 65 40 10 92 0f 0e 67 b9 72 aa 5d e1 03 63
]",,default,false
INSERT,SLT_TEST_1,2015/06/02 14:07:26.860 (Asia/Colombo),1218738496,17,DEBUG3

工作原理:

  • -F,

    将输入字段分隔符设置为逗号。

  • /INSERT/{f=0}

    如果该行包含INSERT,我们会将标记f设置为零(false)。

  • $4==1218738496{f=1}

    如果第四个字段是您选择的号码,那么我们将标志f设置为一个(真)。

  • f

    如果f为真,请打印该行。

使用bash

这使用非常相似的逻辑并产生相同的输出,但使用bash:

#!/bin/bash
f=
while IFS= read line
do
    [[ $line == *"INSERT"* ]] && f=
    IFS=, read a b c d rest <<<"$line"
    [ "$d" = 1218738496 ] && f=1
    [ "$f" ] && echo "$line"
done <file