I'm looking to fetch a value after a match in a string. Lets say I have two string:
string1="Name: John Doe Age: 28 City: Oklahoma City"
string2="Name: Jane Age: 29 Years City: Boston"
Now I want to set three parameters: Name, Age and City. If I were to do:
name=$(echo "$string1" | awk '{ print $2 $3 }')
city=$(echo "$string1" | awk '{ print $5 }')
city=$(echo "$string1" | awk '{ print $8 $9 }
It would work for string1, but obviously not for string2. After some googling I believe I should put it in some kind of array, but I do not really know how to proceed.
Basically, I want everything after Name: and before Age: to be parameter $name . Everything between Age: and City: to be $age , and so on.
Best regards
Needs bash version 3 or higher:
if [[ $string1 =~ ^Name:\ (.*)\ Age:\ (.*)\ City:\ (.*) ]] ; then
name=${BASH_REMATCH[1]}
age=${BASH_REMATCH[2]}
city=${BASH_REMATCH[3]}
fi
You might need Age:\\ ([0-9]*).*\\ City:
if you do not want "Years" to be included in $years
.
Perl solution (taken partly from my answer here ):
Capture name:
name=`perl -ne 'print $1 if /Name: ([a-zA-Z ]+) Age:/' <<< $string`
Capture age:
age=`perl -ne 'print $1 if /Age: ([0-9a-zA-Z ]+) City:/' <<< $string`
-ne tells perl to loop the specified one-liner over the input file or standard input without printing anything by default (you could call it awk emulation mode).
The parens in the regexes specify the bits you're interested in capturing. The other fragments acts as delimiters.
After running both of these through $string1
of your example I get 'John Doe' and '28'.
Edit: replaced echo $string
with <<< $string
, which is nice.
awk
is the best solution for this because you can set the field separator to a regex and then your fields are $2, $3 and $4
name=$(awk -F'[[:alpha:]]+: ' '{print $2}' <<<"$string1")
age=$(awk -F'[[:alpha:]]+: ' '{print $3}' <<<"$string1")
city=$(awk -F'[[:alpha:]]+: ' '{print $4}' <<<"$string1")
Consider these commands:
name=$(awk -F": |Age" '{print $2}' <<< $string1)
age=$(awk -F": |City|Years" '{print $3}' <<< $string1)
city=$(awk -F"City: " '{print $2}' <<< $string1)
Something like this might work:
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
You can use three perl
one-liners for assigning value to your variables -
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)
Test File:
[jaypal:~/Temp] cat file
string1="Name: John Doe Age: 28 City: Oklahoma City"
string2="Name: Jane Age: 29 Years City: Boston"
Name:
[jaypal:~/Temp] perl -pe 's/.*(?<=Name: )([A-Za-z ]+)(?=Age).*/\1/' file
John Doe
Jane
Age:
[jaypal:~/Temp] perl -pe 's/.*(?<=Age: )([A-Za-z0-9 ]+)(?=City).*/\1/' file
28
29 Years
OR
if you just want the age
and not years
then
[jaypal:~/Temp] perl -pe 's/.*(?<=Age: )([0-9 ]+)(?=Years|City).*/\1/' file
28
29
City:
[jaypal:~/Temp] perl -pe 's/.*(?<=City: )([A-Za-z ]+)"/\1/' file
Oklahoma City
Boston
I propose a generic solution:
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
bash-3.2$ cat sample.log
string1="Name: John Doe Age: 28 City: Oklahoma City"
string2="Name: Jane Age: 29 Years City: Boston"
Using awk match inbuilt function:
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
Output:
John Doe : 28 : Oklahoma City
Jane : 29 : Boston
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.