bash: найти неправильные значения в строках - PullRequest
0 голосов
/ 02 января 2012

Я ищу, чтобы получить значение после совпадения в строке.Допустим, у меня есть две строки:

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.После некоторого поиска в Google, я считаю, что я должен поместить его в какой-то массив, но я действительно не знаю, как действовать.

В принципе, я хочу все после Имя: и до Возраст: для параметра $ name .Все между Возраст: и Город: будет $ возраст и т. Д.

С уважением

Ответы [ 8 ]

3 голосов
/ 02 января 2012

Требуется 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.

0 голосов
/ 04 января 2012

bash-3.2 $ cat sample.log

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

Использование awk match встроенная функция:

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
0 голосов
/ 03 января 2012

Я предлагаю общее решение:

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
0 голосов
/ 03 января 2012

Вы можете использовать три 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
0 голосов
/ 02 января 2012

Примерно так может работать:

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
0 голосов
/ 02 января 2012

Рассмотрим эти команды:

name=$(awk -F": |Age" '{print $2}' <<< $string1)
age=$(awk -F": |City|Years" '{print $3}' <<< $string1)
city=$(awk -F"City: " '{print $2}' <<< $string1)
0 голосов
/ 02 января 2012

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")
0 голосов
/ 02 января 2012

Решение Perl (частично взято из моего ответа здесь ):

Имя захвата:

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).

Парены в регулярных выражениях указывают биты, которые вы используете.заинтересованы в захвате.Остальные фрагменты действуют как разделители.

После выполнения обоих из них через $string1 вашего примера я получаю 'John Doe' и '28'.

Редактировать: заменить echo $string на <<< $string, что приятно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...