Витягніть підрядок, використовуючи регулярний вираз у звичайному bash


97

Я намагаюся витягти час із рядка за допомогою 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

Відповіді:


207

Використовуючи чистий :

$ 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

89
    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

8
Я відчуваю, що це зробило мене миттєвим майстром сед. Один хороший варіант, який я можу налаштувати, кращий, ніж дев’ять, якого я не розумію.
Noumenon

Дякую за детальне пояснення, допомагає уникнути майбутніх публікацій "як мені регулярно виразити XXXX".
studgeek

4
Не могли б ви пояснити, чому спочатку придушуєте друк, а -nпотім запитуєте друк знову за допомогою /p? Чи не однаково було б опустити -nпрапор і пропустити /pдирективу? Дякую.
Віктор Замянян,

Чудова відповідь! Дякуємо за допомогу :-)
Бруно Лавіт

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теж працює
Оруелофіл

Дуже чистий і уникає дзвінків до зовнішніх програм.
Віктор Замянян,

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звичайно лише до тих пір, поки положення персонажа не змінюється. що не повинно статися, якщо часовий пояс встановлений.
Маркус,

Питання для сера задається регулярним виразом, а не скороченням
indrajit narvekar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.