LINUX.ORG.RU

Bash regexp

 ,


0

3

Добрый день, прошу помощи с bash'ем. В общем, пишу скрипт, который запускает некую программу и потом должен обработать, то что эта прога вывела на экран. Выводит она строку, что-то в духе: result: 0.1 Time: 9.0

Как можно выделить именно 2 этих числа?

Да тысяча вариантов, но надо смотреть полный вывод работы твоей программы чтоб сказать точно. Из простого

$ echo 'result: 0.1 Time: 9.0' | cut -d ' ' -f 2,4
0.1 9.0
$ echo 'result: 0.1 Time: 9.0' | awk '{print $2" "$4}'
0.1 9.0
alozovskoy ★★★★★
()

в духе

Не знаю уж, в духе или не в духе, но то, что вы привели, разбирается просто по пробелу, безо всяких регулярных выражений.

$ read __ result __ time <<< "result: 0.1 Time: 9.0"
$ echo "$result, $time"
0.1, 9.0
Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 2)
Ответ на: комментарий от Deleted

И что это дает?

Или это вы пытаетесь иронизировать над оборотом «именно 2 этих числа», намекая, что выражаться нужно конкретнее? Так, по-моему, совершенно зазря. Все ОП понятно пишет.

Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

По-моему вообще просили регулярку. Но твой ответ, конечно, лучший из имеющихся, кто-нибудь перечислите ему 10 из моего скора.

alozovskoy ★★★★★
()
Ответ на: комментарий от Zmicier

Классика лоровских клоунов :D

anonymous
()
Ответ на: комментарий от alozovskoy

По-моему вообще просили регулярку.

А пес его знает, что там просили. Но вы правы, конечно, — действительно не стоит полагаться на то, что ввод обязательно будет именно такой, надо проверять. Можно и регуляркой:

[[ $line =~ ^result:\ [0-9]+.[0-9]\ Time:\ [0-9]+.[0-9] ]] || continue

Но я бы наоборот делал:

read _result result _time time <<< "$line"
[[ $_result == result: && $_time == Time: ]] || continue
Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

Это даёт «именно 2 этих числа». Решение согласно условия. Причем в т.ч. исходя из тега regexp.

Вы же пытаетесь думать дальше на один шаг - как этими данными будет пользоваться ОП. И тут Ваше решение вероятнее всего будет наиболее удобным. А пока, до появления ТС'а, это всё отличная практика для прокачивания навыка телепатии :)

Deleted
()
Ответ на: комментарий от Deleted

Ну я собственно уже и вам на один шаг вперед ответил :-), повторяться не буду.

Zmicier ★★★★★
()
Ответ на: комментарий от alozovskoy

Вывод такой:

[20.06.16 19:02:46] [Can] Create CAN
[20.06.16 19:02:46] [Can] Start work with Can
[20.06.16 19:02:46] [Can] Start can-read thread
[Main] Check version file type: 1 for tester with id: 244
[20.06.16 19:02:50] Got answer about check file!
[20.06.16 19:02:50] error_level: 00
[20.06.16 19:02:50] Version fw: 1.21

Когда записываю вывод приложения в переменную:

res='./appication'
То строка получается без переноса по строкам, из-за этого awk не смог подружить (либо я туплю). Пока накатал такие регулярки:
  version=$(expr match "$result" '.* Version fw: \(.*\).*')
  status=$(expr match "$result" '.* error_level: \(.*\)\[')

Так-то работает, но хорошее ли такое решение?

hell_wood
() автор топика
Ответ на: комментарий от hell_wood

Так-то работает, но хорошее ли такое решение?

Первый раз такое вижу, ничего не могу сказать.

То строка получается без переноса по строкам

Тут дело еще в том как читать переменную (есть ли кавычки), вот для примера:

$ cat ./test.sh 
#!/bin/bash

echo foo 123
echo bar 098

$ result=`./test.sh`

$ echo $result 
foo 123 bar 098

$ echo "$result"
foo 123
bar 098

Вариант пользователя Zmicier (выше) хорош потому, что ты получаешь значения в переменные, то есть сможешь с ними дальше работать вообще как вздумается. Вариант с тем же awk просто позволит тебе получить некоторую строку, при этом для того чтоб работать со значениями вне awk придется ее дополнительно парсить.

alozovskoy ★★★★★
()
Ответ на: комментарий от alozovskoy

ну я так и так со своим решением получаю эти значения в переменные.

hell_wood
() автор топика
Ответ на: комментарий от hell_wood

Когда записываю вывод приложения в переменную:
res='./appication'

Здесь вы записываете в переменную res строку ./appication. Вероятно, вы хотели написать res=$(./appication)

То строка получается без переноса по строкам

Не понял, честно говоря.

но хорошее ли такое решение?

Для того, чтобы это сказать, надо видеть всю вашу программу.

Вообще в вызове подпроцессов на каждый чих ничего хорошего нет, но с другой стороны — нужна была бы вам эффективность, вы бы вовсе взяли другой язык и набор средств.

Zmicier ★★★★★
()
Ответ на: комментарий от alozovskoy

да с ковычками затупил. Переписал вот так:

version=$(echo "$var"|awk '/'Version'/ {print $5}')
status=$(echo "$var"|awk '/'error_level'/ {print $4}')

получилось, спасибо!

hell_wood
() автор топика
Ответ на: комментарий от hell_wood

Переписал

Было четыре возможно лишних подпроцесса, стало шесть однозначно лишних. Круто, че.

Zmicier ★★★★★
()
Ответ на: комментарий от hell_wood

Вообще, поскольку у вас серьезные проблемы даже с разбором строки, я бы посоветовал вам показать всю вашу программу — там наверняка есть на что еще обратить ваше внимание.

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)
Ответ на: комментарий от Zmicier

А конкретно разбор вывода, если у вас там на самом деле более двух величин, возможно, целесообразно и вовсе делать как-то так:

declare -A output

sep=': '
while read line; do
    line="${line//\[*\] }" # drop timestamp in brackets
    [[ $line == *$sep* ]] || continue
    key="${line%$sep*}"
    output[$key]="${line##*$sep}"
done

echo "${output[error_level]}, ${output[Version fw]}"
Zmicier ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.