Извлечь строку из строки с помощью RegEx в терминале

У меня есть строка , например first url, second url, third url, и хотелось бы извлечь только url после слова second в терминале OS X (только первое вхождение). Как я могу это сделать?

В моем любимом редакторе я использовал regex /second (url)/ и использовал $1, чтобы извлечь его, я просто не знаю, как это сделать в терминале.

Имейте в виду, что url является фактическим URL-адресом, я буду использовать одно из этих выражений для его соответствия: Regex для соответствия URL

Ответ 1

echo 'first url, second url, third url' | sed 's/.*second//'

Изменить: я неправильно понял. Лучше:

echo 'first url, second url, third url' | sed 's/.*second \([^ ]*\).*/\1/'

или

echo 'first url, second url, third url' | perl -nle 'm/second ([^ ]*)/; print $1'

Ответ 2

В другом ответе вы все еще остаетесь со всем после нужного URL-адреса. Поэтому я предлагаю вам следующее решение.

echo 'first url, second url, third url' | sed 's/.*second \(url\)*.*/\1/'

В sed вы группируете выражение, избегая круглых скобок вокруг него (стандарт POSIX).

Ответ 3

Трубопровод к другому процессу (например, "sed" и "perl", предложенный выше) может быть очень дорогостоящим, особенно если вам нужно выполнить эту операцию несколько раз. Bash поддерживает regexp:

[[ "string" = ~ regex]]

Аналогично тому, как вы извлекаете совпадения в своем любимом редакторе с помощью $1, $2 и т.д., Bash заполняет массив $BASH_REMATCH всеми совпадениями.

В вашем конкретном примере:

str="first usr1, second url2, third url3"
if [[ $str =~ (second )([^,]*) ]]; then echo "match: '${BASH_REMATCH[2]}'"; else echo "no match found"; fi

Вывод:

match: 'url2'

В частности, =~ поддерживает расширенные регулярные выражения как определено POSIX, но с расширениями для платформы (которые различаются по степени и могут быть несовместима).
На платформах Linux (GNU userland) см. man grep; на платформах macOS/BSD, см. man re_format.

Ответ 4

При попытке этого вы, возможно, забыли, это аргумент -E для sed.

От sed --help:

  -E, -r, --regexp-extended
                 use extended regular expressions in the script
                 (for portability use POSIX -E).

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

Это отлично работает для меня:

echo "first url, second url, third url" | sed -E 's/.*second (url).*/\1/'

Вывод:

url

В котором вывод "url" на самом деле является вторым экземпляром в строке. Но если вы уже знаете, что он отформатирован между запятой и пробелом, и вы не разрешаете эти символы в URL-адресах, то регулярное выражение [^,]* должно быть в порядке.

Необязательно:

echo "first http://test.url/1, second ://test.url/with spaces/2, third ftp://test.url/3" \
     | sed -E 's/.*second ([a-zA-Z]*:\/\/[^,]*).*/\1/'

Что правильно выводит:

://example.com/with spaces/2