【问题标题】:find duplicate and execute script on a match查找重复项并在匹配项上执行脚本
【发布时间】:2012-09-27 01:50:24
【问题描述】:

我正在尝试创建一个脚本来解析日志文件并查找每行特定部分的重复匹配项,如果存在重复项,我需要在与重复项匹配的第一行执行脚本。我的日志详细信息是:

#: 177          101 User 1 Channel: SIP/101
#: 178          117 User 2 Channel: SIP/117
#: 179          150 User 3 Channel: SIP/150
#: 356          166 User 4 Channel: SIP/166
#: 387          117 User 2 Channel: SIP/117

我想根据日志文件的 SIP/ 部分查找重复项,但我需要根据日志文件的 # 部分执行脚本。根据这个日志,我需要为 #: 178 行执行一个脚本。

到目前为止我已经使用了

egrep -o ".{50}SIP.{4}"

根据线路的 SIP/ 部分查找重复项。我不清楚如何让整行得到 #: 178 并生成要执行的脚本。

【问题讨论】:

    标签: perl bash grep


    【解决方案1】:

    一种方法:

    grep -nE "$(sed -ne '/^#/s/.*SIP\/\([0-9]*\)$/\1/p' log.txt | sort -n | uniq -d | paste -sd '|')"  log.txt | head -n 1
    

    这将打印(基于您的示例文件):

    2:#: 178          117 User 2 Channel: SIP/117
    

    主要的命令是grep -nE "$(...)" log.txt,它将在你的日志文件中搜索重复的行并打印出来(正则表达式是动态生成的,我将在下面解释)。然后将输出通过管道传送到head -n 1 以仅打印第一行。 grep 命令的 -n 标志打印匹配的实际行号,如果不需要,可以将其删除。

    要生成正则表达式,我们有 4 个命令。

    1. sed -ne '/^#/s/.*SIP\/\([0-9]*\)$/\1/p' log.txt 将仅提取以# 开头的线路上存在的 SIP 号码。
    2. sed 的输出(数字列表)然后通过管道传输以按数字排序
    3. 排序后,我们可以使用uniq -d命令只打印重复的行。
    4. 最后,我们使用paste 命令将所有数字连接在一行中,我们使用-d '|' 选项指定我们想要用'|' 分隔的数字,这是一个正则表达式运算符或。

    因此,正则表达式将查找具有任何一个重复数字的行。

    希望这会有所帮助 =)

    【讨论】:

    • 当我运行你的命令时,它返回了#: 177 101 User 1 Channel: SIP/101
    • 你是如何运行它的?您是否使用 OP 示例的精确副本创建了 log.txt 文件?而且我觉得奇怪的是从行的开头缺少原始行号=S
    • 是的,log.txt 与 OP 的日志文件完全相同。
    【解决方案2】:

    这是使用GNU awk的一种方式:

    awk '$NF in array && !dup[$NF] { print array[$NF]; dup[$NF]++ } { array[$NF]=$2 }' file.txt
    

    结果:

    178
    

    【讨论】:

    • 您应该能够一次性完成此操作 - 在每条记录上,检查相应的数组条目是否存在并在设置数组值之前将其打印出来,然后添加第二个用于跟踪的数组是否已经打印了一个条目(以避免在第三次和后续出现时再次打印)。
    【解决方案3】:

    一次性解决方案。它利用 uniq 支持跳过字段和仅重复标志

    sed -n '/SIP/{s/^#:\s\+\([0-9]\+\).*SIP\/\([0-9]\+\)/\1 \2/;p}' file.txt | sort -k2,2 -n | uniq -f 1 -d | cut -f1 -d ' '
    

    【讨论】:

    • 好主意 =) 我可以建议添加 -n 标志来排序吗?
    • 另一个小建议:也许在 sed 的替代命令中使用p 标志并使用-n 命令行选项?这是为了概括和忽略与模式不匹配的行。
    【解决方案4】:

    AWK 非常适合这种事情。

    这是一个可读的一次性解决方案。

    #!/usr/bin/env awk -f
    
    {
        sip = $3
        script = $2
    
        count[sip]++
    
        if (count[sip] == 1) {
            scripts[sip] = script
        }
        else if (count[sip] > 1) {
            to_run[sip] = scripts[sip]
        }
    }
    
    END {
        for (sip in to_run) {
            print to_run[sip]
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      相关资源
      最近更新 更多