Извлечь подстроку с помощью регулярного выражения в обычном bash

98

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

Моя строка такая:

US/Central - 10:26 PM (CST)

И я хочу извлечь эту 10:26часть.

Кто-нибудь знает способ сделать это только с помощью bash - без использования sed, awk и т.д.?

Например, в PHP я бы использовал - не лучший способ, но он работает - что-то вроде:

preg_match( ""(\d{2}\:\d{2}) PM \(CST\)"", "US/Central - 10:26 PM (CST)", $matches );

Спасибо за любую помощь, даже если в ответе используется sed или awk

Andrux
источник

Ответы:

208

Используя чистый :

$ cat file.txt
US/Central - 10:26 PM (CST)
$ while read a b time x; do [[ $b == - ]] && echo $time; done < file.txt

другое решение с регулярным выражением bash:

$ [[ "US/Central - 10:26 PM (CST)" =~ -[[:space:]]*([0-9]{2}:[0-9]{2}) ]] &&
    echo ${BASH_REMATCH[1]}

другое решение с использованием grepрасширенного регулярного выражения и просмотра:

$ echo "US/Central - 10:26 PM (CST)" | grep -oP "\-\s+\K\d{2}:\d{2}"

другое решение с использованием sed:

$ echo "US/Central - 10:26 PM (CST)" |
    sed 's/.*\- *\([0-9]\{2\}:[0-9]\{2\}\).*/\1/'

другое решение с использованием perl:

$ echo "US/Central - 10:26 PM (CST)" |
    perl -lne 'print $& if /\-\s+\K\d{2}:\d{2}/'

и последний с использованием awk:

$ echo "US/Central - 10:26 PM (CST)" |
    awk '{for (i=0; i<=NF; i++){if ($i == "-"){print $(i+1);exit}}}'
Жиль Кено
источник
Прохладно! Есть ли шанс, что я использую в шаблоне еще и дефис "-"? потому что этот grep возвращает несколько совпадений, и меня интересует только тот, у которого есть дефис, затем пробел, а затем время ...
andrux
Я, наверное, мог бы получить решение на perl, но это отличный плюс. Спасибо!
andrux
добавил awk one для удовольствия =)
Gilles Quenot
1
Спасибо, что сообщили мне о трюке \ K. grep с синтаксисом perl действительно мощный.
Марко Сулла
1
Мне нравится sedверсия, но я хотел предупредить других, что sedне обязательно использовать +модификатор. Один из способов обойти {1, }эту проблему - использовать модификатор для соответствия одному или нескольким.
CodeBrew
90
    echo "US/Central - 10:26 PM (CST)" | sed -n "s/^.*-\s*\(\S*\).*$/\1/p"

-n      suppress printing
s       substitute
^.*     anything at the beginning
-       up until the dash
\s*     any space characters (any whitespace character)
\(      start capture group
\S*     any non-space characters
\)      end capture group
.*$     anything at the end
\1      substitute 1st capture group for everything on line
p       print it
Jgshawkey
источник
8
Я чувствую, что это сделало меня мастером sed. Один хороший вариант, который я могу настроить, лучше девяти, я не понимаю.
Ноумен
Спасибо за подробное объяснение, помогающее избежать будущих сообщений "как мне использовать регулярное выражение XXXX".
Studgeek
4
Не могли бы вы объяснить, почему вы сначала подавляете печать, а -nзатем снова запрашиваете печать с помощью /p? Разве это не то же самое, что опустить -nфлаг и опустить /pдирективу? Спасибо.
Виктор Заманян 02
Отличный ответ! Спасибо за вашу помощь :-)
Бруно Лавит 08
1
@VictorZamanian отсюда : «По умолчанию sed печатает каждую строку. Если он выполняет замену, вместо старого печатается новый текст. Если вы используете необязательный аргумент sed,« sed -n », этого не произойдет, по умолчанию выводить любые новые строки. ... Когда используется опция "-n", флаг "p" приводит к печати измененной строки. "
tdashroy
26

Быстрый и грязный, без регулярных выражений, малонадежный метод измельчения и измельчения

string="US/Central - 10:26 PM (CST)"
etime="${string% [AP]M*}"
etime="${etime#* - }"
удвоить
источник
5
Это настолько отвратительно грязно, что мне стыдно, что я сам не подумал об этом. +1 | read zone dash time apm zoneтоже работает
Орвеллофил
Очень чистый и избегает вызовов внешних программ.
Виктор Заманян 02
8
Привет, это было бы в 10 раз полезнее, если бы в него была включена ссылка на дополнительную документацию или некоторые имена, связанные с этой техникой, чтобы люди могли пойти и исследовать больше. Для заинтересованных, это манипуляции со строками в bash, и вы можете найти более подробную информацию здесь: tldp.org/LDP/abs/html/string-manipulation.html
Педро Мата-Мурос
0

Если ваша строка

foo="US/Central - 10:26 PM (CST)"

затем

echo "${foo}" | cut -d ' ' -f3

сделаю свою работу.

ЛеЧатДеНансен
источник
1
или, cut -c14-18конечно, только до тех пор, пока позиция персонажа не меняется. чего не должно происходить, если часовой пояс фиксирован.
Маркус
Сэр вопрос задан для регулярного выражения, а не для сокращения
индраджит нарвекар