bash:在字符串中查找不规则值

时间:2012-01-02 18:58:22

标签: string bash

我想在字符串中匹配后获取值。 可以说我有两个字符串:

string1="Name: John Doe Age: 28 City: Oklahoma City"
string2="Name: Jane Age: 29 Years City: Boston"

现在我想设置三个参数:名称,年龄和城市。 如果我这样做:

name=$(echo "$string1" | awk '{ print $2 $3 }')
city=$(echo "$string1" | awk '{ print $5 }')
city=$(echo "$string1" | awk '{ print $8 $9 }

它适用于string1,但显然不适用于string2。 经过一些谷歌搜索我相信我应该把它放在某种阵列中,但我真的不知道如何继续。

基本上,我希望 Name:之后和 Age:之前的所有内容都是参数 $ name 年龄:城市:之间的所有内容都是 $ age ,依此类推。

祝你好运

8 个答案:

答案 0 :(得分:3)

需要bash版本3或更高版本:

if [[ $string1 =~ ^Name:\ (.*)\ Age:\ (.*)\ City:\ (.*) ]] ; then
    name=${BASH_REMATCH[1]}
    age=${BASH_REMATCH[2]}
    city=${BASH_REMATCH[3]}
fi

如果您不希望“年”包含在Age:\ ([0-9]*).*\ City:中,则可能需要$years

答案 1 :(得分:0)

Perl解决方案(部分来自我的回答here):

捕获名称:

name=`perl -ne 'print $1 if /Name: ([a-zA-Z ]+) Age:/' <<< $string`

捕获年龄:

age=`perl -ne 'print $1 if /Age: ([0-9a-zA-Z ]+) City:/' <<< $string`

-ne告诉perl在输入文件或标准输入上循环指定的单行,而不默认打印任何东西(你可以称之为awk仿真模式)。

正则表达式中的parens指定了您有兴趣捕获的位。其他片段充当分隔符。

通过你的例子$string1运行这两个后,我得到'John Doe'和'28'。

修改:将echo $string替换为<<< $string,这很不错。

答案 2 :(得分:0)

awk是最佳解决方案,因为您可以将字段分隔符设置为正则表达式,然后您的字段为$ 2,$ 3和$ 4

name=$(awk -F'[[:alpha:]]+: ' '{print $2}' <<<"$string1")
 age=$(awk -F'[[:alpha:]]+: ' '{print $3}' <<<"$string1")
city=$(awk -F'[[:alpha:]]+: ' '{print $4}' <<<"$string1")

答案 3 :(得分:0)

考虑以下命令:

name=$(awk -F": |Age" '{print $2}' <<< $string1)
age=$(awk -F": |City|Years" '{print $3}' <<< $string1)
city=$(awk -F"City: " '{print $2}' <<< $string1)

答案 4 :(得分:0)

这样的事可能有用:

string1="Name: John Doe Age: 28 City: Oklahoma City"
string1ByRow=$(echo "$string1" | perl -pe 's/(\w+:)/\n$1\n/g' | sed '/^$/d' | sed 's/^ *//')
string1Keys=$(echo "$string1ByRow" | grep ':$' | sed 's/:$//')
string1Vals=$(echo "$string1ByRow" | grep -v ':$')

echo "$string1Keys"
Name
Age
City

echo "$string1Vals"
John Doe 
28 
Oklahoma City

答案 5 :(得分:0)

您可以使用三个perl单行来为变量赋值 -

name=$(perl -pe 's/.*(?<=Name: )([A-Za-z ]+)(?=Age).*/\1/' file)

age=$(perl -pe 's/.*(?<=Age: )([A-Za-z0-9 ]+)(?=City).*/\1/' file)

OR

age=$(perl -pe 's/.*(?<=Age: )([0-9 ]+)(?=Years|City).*/\1/' file)

city=$(perl -pe 's/.*(?<=City: )([A-Za-z ]+)"/\1/' file)

测试文件:

[jaypal:~/Temp] cat file
string1="Name: John Doe Age: 28 City: Oklahoma City"
string2="Name: Jane Age: 29 Years City: Boston"

命名

[jaypal:~/Temp] perl -pe 's/.*(?<=Name: )([A-Za-z ]+)(?=Age).*/\1/' file
John Doe 
Jane 

<强>年龄:

[jaypal:~/Temp] perl -pe 's/.*(?<=Age: )([A-Za-z0-9 ]+)(?=City).*/\1/' file
28 
29 Years 


    如果你只想要agenot years那么

[jaypal:~/Temp] perl -pe 's/.*(?<=Age: )([0-9 ]+)(?=Years|City).*/\1/' file
28 
29 

<强>城市:

[jaypal:~/Temp] perl -pe 's/.*(?<=City: )([A-Za-z ]+)"/\1/' file
Oklahoma City
Boston

答案 6 :(得分:0)

我提出了一个通用解决方案:

keys=() values=()
for word in $string; do
    wlen=${#word}
    if [[ ${word:wlen-1:wlen} = : ]]; then
        keys+=("${word:0:wlen-1}") values+=("")
    else
        alen=${#values[@]}
        values[alen-1]=${values[alen-1]:+${values[alen-1]} }$word
    fi
done

答案 7 :(得分:0)

bash-3.2 $ cat sample.log

string1="Name: John Doe Age: 28 City: Oklahoma City"
string2="Name: Jane Age: 29 Years City: Boston"

使用awk 匹配内置函数:

awk ' { match($0,/Name:([A-Za-z ]*)Age:/,a); match($0,/Age:([ 0-9]*)/,b);  match($0,/City:([A-Za-z ]*)/,c); print a[1]":" b[1]":"c[1] } ' sample.log

输出:

 John Doe : 28 : Oklahoma City
 Jane : 29 : Boston