Shell脚本 - 匹配特定命名字段中的值

时间:2013-09-05 13:53:59

标签: bash shell unix

例如,我们假设我们有以下一行:

RESULT: test=abc slave=def owners=own1,test,own2,newown time=32 status=fail

这里测试,奴隶,所有者,时间和状态是不同的属性。 属性的数量可以变化,即可以存在类别= xyz等其他属性,或者某些属性可能不存在。

我正在寻找一个匹配的正则表达式,如果“owners =”包含一个特定的所有者,比如说“own2”。此外,此正则表达式不应与行中的其他匹配项匹配。例如,行可以是:

RESULT: test=own2 slave=def owners=own1,test,own2,newown time=32 status=fail

正则表达式不应与“test”属性的own2匹配。

我花了几个小时搜索但失败了:(

我用egrep寻找正则表达式。我尝试了以下方法:

line="RESULT: test=abc slave=def owners=own1,test,own2,newown time=32 status=fail"
echo $line | egrep "owners=*own2*"

这无法返回任何值。我的正则表达式没有问题。

我正在寻找适用于所有Unix风格的东西,如Linux,AIX,Solaris等。

编辑 - 现在与示例

非常感谢您的回复!

让我用更清楚的例子来解释:

myfile的内容:

blabla  
blaaaaaa some text  
RESULT: test=abcgrp1 slave=def owners=test,own2,newown time=32 status=fail  

some more blabla  
xyze  
RESULT: test=abc1 slave=def owners=grp1,test time=32 status=pass  

some text here  
RESULT: test=abc2 slave=def owners=gr,grp1 time=32 status=pass  

我想获得状态为“通过”且其“所有者”为“grp1”或“grp2”的测试。 所以,最初,我写道:

grep RESULT myfile | grep "pass" | egrep "grp1|gpr2"  

没有花太多时间意识到这是不正确的,因为它对“myfile”中的第一个“RESULT”行返回true。

所以,我想这样写:

grep RESULT myfile | grep "pass" | egrep "owners=grp1|owners=gpr2"  

显然,对于“myfile”中的第三个“RESULT”行,这将失败。

所以,我需要一个正则表达式,只有当模式出现在“所有者”列表中的任何地方时才会匹配。

注意:如果“所有者”列表包含多个所有者,则会以逗号分隔。否则,它只有一个值。例如:owner = abc

希望我的问题现在更清楚了。

6 个答案:

答案 0 :(得分:1)

给定文件

$ cat file
RESULT: test=abc slave=def owners=own1,test,own2,newown time=32 status=fail

此grep表达式仅显示owners=之后的内容:

$ grep -Po '(?<=owners=)\w+' file
own1

如果文件包含更多信息,则无关紧要:

$ cat file
RESULT: test=abc slave=def owners=own1,hello=3,test,own2,newown time=32 status=fail, more things
$ grep -Po '(?<=owners=)\w+' file
own1

使用此文本,您可以继续if条件:

if [[ "$(grep -Po '(?<=owners=)\w+' file)" == *own1* ]]; then
   echo "it is there"
fi

试验:

$ if [[ "$(grep -Po '(?<=owners=)\w+' file)" == *own1* ]]; then echo "it is there"; fi
it is there

答案 1 :(得分:1)

您可以使用:

echo "$line" | grep -E '\<owners=([[:alnum:]]+,)*own2($|[, ])'

这将找到包含所有者值的任何字符串,其逗号分隔值包含own2

答案 2 :(得分:1)

Pure bash解决方案:

line='RESULT: test=abc slave=def owners=own1,test,own2,newown time=32 status=fail'

declare -A allValues
while read -r -d ' ' curValue; do
    IFS='=' read key value <<< "${curValue}"
    allValues["$key"]=$value
done <<< "${line#RESULT: } "

这会创建一个很好的关联数组。现在很容易获得任何价值:

echo "${allValues[slave]}" # prints 'def'
echo "${allValues[owners]}" # prints 'own1,test,own2,newown'

现在,要查看own2是否真的存在,您可以使用=~

if [[ ${allValues[owners]} =~ own2 ]]; then

或使用globs:

if [[ ${allValues[owners]} = *own2* ]]; then

编辑:

糟糕!

想象一下这样的数据:owners=own1,test,thisown2iswrong,newown
之前的两个解决方案都将返回true,这可能不是您想要的 这是一个更好的正则表达式:

if [[ ${allValues[owners]} =~ (^|,)own2(,|$) ]]; then

答案 3 :(得分:0)

你有没有尝试过:

echo "RESULT: test=abc slave=def owners=own1,test,own2,newown time=32 status=fail" | grep "owners=[^ ]*own2"

示例:

$ echo "RESULT: test=abc slave=def owners=own1,test,own2,newown time=32 status=fail" | grep -Po "owners=\K[^ ]*own[0-9]"
own1,test,own2

您可能想说:

echo $line | egrep "owners=.*own2.*"

(注意模式中的额外.

答案 4 :(得分:0)

你走了。这个脚本需要GNU Awk(gawk)。

#!/usr/bin/gawk -f

function parse_file(file,  a, count, id, key, text, values) {
    FS = " "
    id = 0
    while ((getline < file) > 0) {
        if (!/^[[:blank:]]*$/) {
            text = ""
            do {
                if (/^RESULT: /) {
                    tests[id] = text
                    tests_results[id] = $0
                    count = split($0, props)
                    for (i = 2; i <= count; ++i) {
                        match(props[i], /([^=]+)=?(.*)/, a)
                        key = a[1]; values = a[2]
                        if (length(tests_props[id])) {
                            tests_props[id] = tests_props[id] "|" key
                        } else {
                            tests_props[id] = key
                        }
                        tests_props[id "|" key] = values
                    }
                    break
                } else {
                    if (length(text)) {
                        text = text "\n" $0
                    } else {
                        text = $0
                    }
                }
            } while ((getline < file) > 0)
            ++id
        }
    }
    tests_count = id
}

function get_values(id, key, var,  a, i, t, v) {
    v = tests_props[id "|" key]
    split(v, a, /,/)
    delete var
    for (i = 1; i in a; ++i) {
        t = a[i]
        var[t] = t
    }
}

function print_test(id) {
    print "--------------------"
    print tests[id]
    print tests_results[id]
    print "--------------------"

}

BEGIN {
    parse_file(ARGV[1])
    for (i in tests) {
        get_values(i, "owners", owners)
        get_values(i, "status", status)
        if (("grp1" in owners || "grp2" in owners) && "pass" in status) {
            print_test(i)
        }
    }
    exit
}

示例文件:

blabla  
blaaaaaa some text  
RESULT: test=abcgrp1 slave=def owners=test,own2,newown time=32 status=fail  

some more blabla  
xyze  
RESULT: test=abc1 slave=def owners=grp1,test time=32 status=pass  

some text here  
RESULT: test=abc2 slave=def owners=gr,grp1 time=32 status=pass  

some more blabla  
xyze  
RESULT: test=abc1 slave=def owners=grp1,test time=32 status=pass

正在运行gawk -f script.awk sample.txt

--------------------
some more blabla  
xyze  
RESULT: test=abc1 slave=def owners=grp1,test time=32 status=pass  
--------------------
--------------------
some text here  
RESULT: test=abc2 slave=def owners=gr,grp1 time=32 status=pass  
--------------------
--------------------
some more blabla  
xyze  
RESULT: test=abc1 slave=def owners=grp1,test time=32 status=pass
--------------------

代码应该可以根据自己的要求轻松定制。请问我是否需要帮助。

答案 5 :(得分:0)

非常感谢您的见解和答案。

以下结果:

grep RESULT myfile | grep "pass" | egrep \(\(owners=\)*\(grp1\)\|\(owners=\)*\(grp2\)\)

据我所知,

1)当您有多个模式时,请将它们括在括号中

2)如果有多个这样的图案,它们应该用管子分开,并且应该有另一个括号覆盖所有图案

如果只有一个这样的图案,则覆盖括号是可选的。这适用于我测试的所有平台,即AIX,HPUX,LINUX,SOLARIS和NT。