我想在字符串中匹配后获取值。 可以说我有两个字符串:
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 ,依此类推。
祝你好运
答案 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
或强>
如果你只想要age
和not 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