4

Я пытаюсь использовать sed для извлечения части значения одной из множества пар ключ-значение в строке запроса URL

Вот что я пытаюсь:

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's@^https?://(www.)?youtube.com/(watch\\?)?.*?v(=|/)([a-zA-Z0-9\-_]*)(&.*)?$@$4@'

но он всегда выводит входной URL как есть.

Что я делаю неправильно?

Обновление 1

Чтобы уточнить некоторые вопросы:

  1. Регулярное выражение является более сложным, чем должно быть, потому что я также пытаюсь проверить правильность ввода и сгенерировать вывод, только если вход действителен. Так что более строгий матч.
  2. Желаемым выводом является значение ключа 'v' в строке запроса.
  3. Я не смог найти версию sed которую я использую, но она поставляется с Mac OS X (10.7.5).
  4. В моей версии sed $ 1, $ 2 и т.д. Кажутся совпадениями, \1, \2 и т.д. Выдают ошибку: sed: 1: "s@^https?://(www.)?yout ...": \4 not defined in the RE Не правильно!как я узнал позже. Извиняюсь за то, что вызвал путаницу.

Обновление 2

Обновили sed RE, чтобы сделать его более конкретным, основываясь на предложении @slhck ниже, но проблема остается прежней.

Обновление 3

Исходя из man страницы для этой версии sed кажется, что это версия со вкусом BSD.

5 ответов5

11

Еще проще, если вы просто хотите abc:

 echo 'http://www.youtube.com/watch?v=abc&g=xyz' | awk -F'[=&]' '{print $2}'

Если вы хотите xyz :

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | awk -F'[=&]' '{print $4}'

ОБЪЯСНЕНИЕ:

  • awk : это язык сценариев, который автоматически обрабатывает входные файлы построчно, разбивая каждую строку на поля. Таким образом, когда вы обрабатываете файл с помощью awk , для каждой строки первое поле равно $1 , второе $2 т.д. До $N По умолчанию awk использует пробелы в качестве разделителя полей.

  • -F'[=&]' : -F используется для изменения разделителя поля с пробелов на что-то еще. В этом случае я даю ему класс персонажей. Квадратные скобки ([ ]) используются многими языками для обозначения групп символов. Так, в частности, -F'[=&]' означает, что awk должен использовать оба & и = качестве разделителей полей.

  • Поэтому, учитывая входную строку из вашего вопроса, используя & и = качестве разделителей, awk будет читать следующие поля:

    http://www.youtube.com/watch?v=abc&g=xyz
    |----------- $1 -------------| --- - ---      
                                    |  |  |
                                    |  |  ̣----- $4
                                    |  -------- $3
                                    ----------- $2
    

    Итак, все, что вам нужно сделать, это напечатать тот, который вы хотите {print $4} .


Вы сказали, что хотите также проверить, что строка является действительным URL-адресом YouTube, вы не можете сделать это с помощью sed поскольку если он не соответствует заданному вами регулярному выражению, он просто напечатает всю строку. Вы можете использовать такой инструмент, как Perl чтобы печатать, только если регулярное выражение соответствует:

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | 
  perl -ne 's/http.*www.youtube.com\/watch\?v=(.+?)&.+/$1/ && print'

И, наконец, просто напечатать abc вы можете использовать стандартные UNIX инструмент cut:

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | 
  cut -d '=' -f 2 | cut -d '&' -f 1
2

если вам нужен "xyz", попробуйте это (GNU sed):

echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's/.*=\([[:alnum:]]*\).*/\1/'
2

Эксперименты с sed основанные на ответах @Endoro и @slhck, привели меня к окончательному ответу (тот, который я хотел). Вот что у меня работает с версией sed на Mac OS X (10.7.5):

echo 'http://www.youtube.com/watch?v=dnCkNz_xrpg' | sed -E 's@https?://(www\.)?youtube.com/(watch\?).*v=([-_a-zA-Z0-9]*).*@\3@'

Объяснение:

  1. -E , чтобы заставить sed использовать расширенный RE. В других версиях sed -r может быть эквивалентной опцией.
  2. RE, казалось бы, более сложный, чем он должен быть, должен также убедиться, что это действительная ссылка на YouTube. Измените начальные части этого RE, как требуется (например, https?://(www\.)?example.com/(.*\?).*key=([^&]*).*)
  3. \3 соответствует 3 -му выражению в скобках и выводит его как ответ / совпадение (что я и хочу).
  4. Используя 's @@@' вместо обычного 's ///', чтобы мне не приходилось избегать много косых черт (\) в URL.

Надеюсь, что это помогает другим, так как мне помогли.

1

Если вы на самом деле просто хотите получить идентификатор видео - так, что-нибудь между v= и следующим & - просто используйте:

sed -r 's/.*v=([[:alnum:]]*).*/\1/'

Вот что не так с вашей командой:

  • -r необходим для использования расширенных регулярных выражений. Если вы пропустите это, sed интерпретирует скобки буквально, поэтому не будет никаких групп соответствия. В случае BSD sed используйте опцию -E .

  • Вы используете $1 для ссылки на совпадения, но вы должны использовать \1 . Например, $1 - это аргумент оболочки, передаваемый текущему сценарию.

  • Вы должны использовать класс символов, например [[:alnum:]] (или [a-zA-Z0-9_] зависимости от того, как настроены идентификаторы), чтобы соответствовать значению параметра, так как в противном случае будет также записан следующий символ & , Регулярное выражение является жадным и будет просто соответствовать abc&g=xyz если вы используете .*? Поскольку ленивое количественное определение не поддерживается в BRE/ERE, а только в регулярных выражениях Perl или других "современных" разновидностях.

0

Он всегда отображает URL, потому что SED не соответствует ему.

    echo 'http://www.youtube.com/watch?v=abc&g=xyz' | sed 's!^http://www.youtube.com/watch\?\(.*=.*\)&\(.*=.*\)!\1!'

Будет отображать v = abc

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .