Я пытаюсь использовать sed для очистки строк URL, чтобы извлечь только домен.
Итак, из:
http://www.suepearson.co.uk/product/174/71/3816/
Я хочу:
(либо с косой чертой, либо без нее, это не имеет значения)
Я пробовал:
sed 's|\(http:\/\/.*?\/\).*|\1|'
и (ускользание от неживого квантора)
sed 's|\(http:\/\/.*\?\/\).*|\1|'
но я не могу заставить работать не жадный квантификатор, поэтому он всегда заканчивается совпадением всей строки.
Ни основное, ни расширенное Posix/GNU regex не распознают неживой квантификатор; вам потребуется более позднее регулярное выражение. К счастью, регулярное выражение Perl для этого контекста довольно легко получить:
perl -pe 's|(http://.*?/).*|\1|'
-pi -e
.
Попробуйте [^/]*
вместо .*?
:
sed 's|\(http://[^/]*/\).*|\1|g'
С sed я обычно реализую нежирный поиск, ища что-либо, кроме разделителя, до разделителя:
echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*\)/.*;\1;p'
Вывод:
http://www.suon.co.uk
это:
-n
s/<pattern>/<replace>/p
;
поиск разделителя команд вместо /
, чтобы облегчить ввод типа s;<pattern>;<replace>;p
\(
... \)
, позже доступными с помощью \1
, \2
...http://
[]
, [ab/]
будет означать либо a
, либо b
или /
^
в []
означает not
, за которым следует что-либо, кроме вещи в []
[^/]
означает что-либо, кроме символа /
*
- повторять предыдущую группу, поэтому [^/]*
означает символы, кроме /
.sed -n 's;\(http://[^/]*\)
означает поиск и запоминание http://
, за которым следуют любые символы, кроме /
, и помните, что вы нашли/
, поэтому добавьте еще один /
в конец: sed -n 's;\(http://[^/]*\)/'
, но мы хотим сопоставить остальную часть строки после домена, поэтому добавьте .*
\1
), является доменом, поэтому замените соответствующую строку на материал, сохраненный в группе \1
, и напечатайте: sed -n 's;\(http://[^/]*\)/.*;\1;p'
Если вы хотите включить обратную косую черту после домена, а затем добавьте еще одну обратную косую черту в группе, чтобы запомнить:
echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*/\).*;\1;p'
выход:
http://www.suon.co.uk/
sed не поддерживает "не жадный" оператор.
Вы должны использовать оператор "[]", чтобы исключить "/" из соответствия.
sed 's,\(http://[^/]*\)/.*,\1,'
P.S. нет необходимости обратного слэш "/".
Этот поток действительно старый, но я предполагаю, что люди все еще нуждаются в нем.
Допустим, вы хотите убить все до самого первого появления HELLO
. Вы не можете сказать [^HELLO]
...
Итак, хорошее решение включает в себя два шага, предполагая, что вы можете зарезервировать уникальный символ, которого вы не ожидаете на входе, например `
(обратная сторона).
В этом случае мы можем:
s_HELLO_`_ #will only replace the very first occurrence
s_.*`__ #kill everything till end of the first HELLO
НТН!
Это можно сделать с помощью cut:
echo "http://www.suepearson.co.uk/product/174/71/3816/" | cut -d'/' -f1-3
sed
И все другие ароматы регулярных выражений!
Поиск первого вхождения выражения:
POSIX ERE (с использованием опции -r
)
Regex:
(EXPRESSION).*|.
Sed:
sed -r "s/(EXPRESSION).*|./\1/g" # Global `g` modifier should be on
Пример (поиск первой последовательности цифр) Живая демонстрация:
$ sed -r "s/([0-9]+).*|./\1/g" <<< "foo 12 bar 34"
12
Как это работает?
Это регулярное выражение извлекает выгоду из чередования |
. В каждой позиции движок будет искать первую сторону чередования (наша цель), и если она не соответствует второй стороне чередования, которая имеет точку .
, соответствует следующему непосредственному символу.
Поскольку глобальный флаг установлен, движок пытается продолжить сопоставление символов по символам до конца строки ввода или нашей цели. Как только первая и единственная группа захвата левой стороны чередования сопоставляется (EXPRESSION)
, остальная часть линии также потребляется сразу же .*
. Теперь мы удерживаем наше значение в первой группе захвата.
POSIX BRE
Regex:
\(\(\(EXPRESSION\).*\)*.\)*
Sed:
sed "s/\(\(\(EXPRESSION\).*\)*.\)*/\3/"
Пример (поиск первой последовательности цифр):
$ sed "s/\(\(\([0-9]\{1,\}\).*\)*.\)*/\3/" <<< "foo 12 bar 34"
12
Этот вариант похож на версию ERE, но без чередования. Все это. В каждой отдельной позиции двигатель пытается сопоставить цифру.
Если он найден, другие следующие разряды расходуются и захватываются, а оставшаяся строка соответствует немедленно, так как *
означает
больше или равно нулю, он пропускает вторую группу захвата \(\([0-9]\{1,\}\).*\)*
и достигает точки .
для соответствия одному символу, и этот процесс продолжается.
Поиск первого появления выражения с разделителями:
Этот подход будет соответствовать самому первому вхождению строки, которая ограничена. Мы можем назвать это блоком строки.
sed "s/\(END-DELIMITER-EXPRESSION\).*/\1/; \
s/\(\(START-DELIMITER-EXPRESSION.*\)*.\)*/\1/g"
Строка ввода:
foobar start block #1 end barfoo start block #2 end
-EDE: end
-SDE: start
$ sed "s/\(end\).*/\1/; s/\(\(start.*\)*.\)*/\1/g"
Вывод:
start block #1 end
Первое регулярное выражение \(end\).*
сопоставляет и фиксирует разделитель первого конца end
и заменяет все совпадения последними захваченными символами, которые
является конечным разделителем. На этом этапе наш выход: foobar start block #1 end
.
Затем результат передается во второе регулярное выражение \(\(start.*\)*.\)*
, которое аналогично предыдущей версии POSIX BRE. Он соответствует одному символу
если разделитель начала start
не соответствует, иначе он соответствует и фиксирует разделитель начала и соответствует остальным символам.
Используя подход №2 (выражение с разделителями), вы должны выбрать два подходящих выражения:
EDE: [^:/]\/
SDE: http:
Использование:
$ sed "s/\([^:/]\/\).*/\1/g; s/\(\(http:.*\)*.\)*/\1/" <<< "http://www.suepearson.co.uk/product/174/71/3816/"
Вывод:
http://www.suepearson.co.uk/
другим способом, не использующим регулярное выражение, является использование методов полей/разделителей, например
string="http://www.suepearson.co.uk/product/174/71/3816/"
echo $string | awk -F"/" '{print $1,$2,$3}' OFS="/"
sed
конечно же имеет свое место, но это не один из них!
Как сказал Ди: Просто используйте cut
. В этом случае он намного проще и безопаснее. Здесь пример, где мы извлекаем различные компоненты из URL с помощью синтаксиса Bash:
url="http://www.suepearson.co.uk/product/174/71/3816/"
protocol=$(echo "$url" | cut -d':' -f1)
host=$(echo "$url" | cut -d'/' -f3)
urlhost=$(echo "$url" | cut -d'/' -f1-3)
urlpath=$(echo "$url" | cut -d'/' -f4-)
дает вам:
protocol = "http"
host = "www.suepearson.co.uk"
urlhost = "http://www.suepearson.co.uk"
urlpath = "product/174/71/3816/"
Как вы можете видеть, это намного более гибкий подход.
(все кредиты Ди)
sed -E интерпретирует регулярные выражения как расширенные (современные) регулярные выражения
Обновление: -E на MacOS X, -r в GNU sed.
-E
уникален для BSD sed
и, следовательно, для OS X. Ссылки на справочные страницы. -r
вносит расширенные регулярные выражения в GNU sed
как отмечалось в исправлении @ stephancheg. Остерегайтесь при использовании команды известной изменчивости между дистрибутивами 'nix. Я узнал, что трудный путь.
sed - не жадное соответствие Кристофа Зигарта
Трюк, чтобы получить нежеланное совпадение в sed, соответствует всем символам, за исключением того, что завершает совпадение. Я знаю, без проблем, но я потратил драгоценные минуты на это, и сценарии оболочки должны быть, в конце концов, быстрыми и легкими. Поэтому, если кому-то это может понадобиться:
Жадное соответствие
% echo "<b>foo</b>bar" | sed 's/<.*>//g'
bar
Нежелательное соответствие
% echo "<b>foo</b>bar" | sed 's/<[^>]*>//g'
foobar
Есть еще надежда решить эту проблему с помощью чистого (GNU) sed. Несмотря на то, что это не общее решение, в некоторых случаях вы можете использовать "петли", чтобы исключить все ненужные части строки, например:
sed -r -e ":loop" -e 's|(http://.+)/.*|\1|' -e "t loop"
Единственная проблема здесь - это также сократить последний разделительный символ ('/'), но если вам это действительно нужно, вы можете просто вернуть его после завершения цикла, просто добавьте эту дополнительную команду в конец предыдущей командной строки:
-e "s,$,/,"
sed 's|(http:\/\/[^\/]+\/).*|\1|'
Поскольку вы конкретно заявили, что пытаетесь использовать sed (вместо perl, cut и т.д.), попробуйте сгруппировать. Это обходит ненасытный идентификатор, который потенциально не распознается. Первой группой является протокол (т.е. "Http://", "https://", "tcp://" и т.д.). Вторая группа - это домен:
echo "http://www.suon.co.uk/product/1/7/3/" | sed "s|^\(.*//\)\([^/]*\).*$|\1\2|"
Если вы не знакомы с группировкой, запустите здесь.
Вот что вы можете сделать с помощью двухэтапного подхода и awk:
A=http://www.suepearson.co.uk/product/174/71/3816/
echo $A|awk '
{
var=gensub(///,"||",3,$0) ;
sub(/\|\|.*/,"",var);
print var
}'
Вывод: http://www.suepearson.co.uk
Надеюсь, что это поможет!
Другая версия sed:
sed 's|/[:alphanum:].*||' file.txt
Он соответствует /
, за которым следует буквенно-цифровой символ (а не другая косая черта), а также остальные символы до конца строки. Впоследствии он заменяет его ничем (т.е. Удаляет его.)
sed 's|\(http:\/\/www\.[a-z.0-9]*\/\).*|\1|
работает тоже
Я понимаю, что это старая запись, но кто-то может найти ее полезной. Поскольку полное доменное имя не может превышать общую длину в 253 символа, замените. * С. \{1, 255 \}
echo "/home/one/two/three/myfile.txt" | sed 's|\(.*\)/.*|\1|'
Надеюсь, я получил его на другом форуме:)
/home/one/two/three/
, если вы добавите другое /
like /home/one/two/three/four/myfile.txt
вы тоже жадно сопоставите four
: /home/one/two/three/four
, вопрос о не жадных