Estoy tratando de usar sed para limpiar las líneas de URL para extraer solo el dominio.
Entonces desde:
http://www.suepearson.co.uk/product/174/71/3816/
Yo quiero:
http://www.suepearson.co.uk/
(ya sea con o sin la barra de entrenamiento, no importa)
Yo he tratado:
sed 's|\(http:\/\/.*?\/\).*|\1|'
y (escapando del cuantificador no codicioso)
sed 's|\(http:\/\/.*\?\/\).*|\1|'
pero parece que no puedo lograr que funcione el cuantificador no codicioso, por lo que siempre termina emparejando toda la cadena.
Ni la expresión regular Posix / GNU básica ni extendida reconoce el cuantificador no codicioso; necesitas una expresión regular posterior. Afortunadamente, Perl Regex para este contexto es bastante fácil de obtener:
perl -pe 's|(http://.*?/).*|\1|'
Pruebe con [^/]*
lugar de .*?
:
sed 's|\(http://[^/]*/\).*|\1|g'
Con sed, suelo implementar búsquedas no codiciosas buscando cualquier cosa excepto el separador hasta el separador:
echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*\)/.*;\1;p'
Salida:
http://www.suon.co.uk
esto es:
-n
s///p
;
Busque el separador de comandos en lugar de /
para que sea más fácil escribir so s;;;p
\(
… \)
, más tarde accesible con \1
, \2
… http://
[]
, [ab/]
significaría a
o b
o /
^
en []
significa not
, seguido de cualquier cosa que no sea la cosa en []
[^/]
significa algo excepto /
personaje *
es para repetir el grupo anterior así que [^/]*
significa caracteres excepto /
. sed -n 's;\(http://[^/]*\)
significa buscar y recordar http://
seguido de cualquier caracter excepto /
y recordar lo que has encontrado /
así que agregue otro /
al final: sed -n 's;\(http://[^/]*\)/'
pero queremos hacer coincidir el rest de la línea después del dominio así que agregue .*
\1
) es el dominio así que reemplace la línea coincidente con cosas guardadas en el grupo \1
e imprima: sed -n 's;\(http://[^/]*\)/.*;\1;p'
Si también desea incluir una barra invertida después del dominio, agregue una barra invertida más en el grupo para recordar:
echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*/\).*;\1;p'
salida:
http://www.suon.co.uk/
sed no es compatible con el operador “no codicioso”.
Debe usar el operador “[]” para excluir “/” de la coincidencia.
sed 's,\(http://[^/]*\)/.*,\1,'
PS no hay necesidad de barra invertida “/”.
Este hilo es muy viejo, pero supongo que la gente aún lo necesita. Digamos que quieres matar todo hasta la primera aparición de HELLO
. No puedes decir [^HELLO]
…
De modo que una buena solución implica dos pasos, suponiendo que se puede ahorrar una palabra única que no se espera en la entrada, digamos top_sekrit
.
En este caso, podemos:
s/HELLO/top_sekrit/ #will only replace the very first occurrence s/.*top_sekrit// #kill everything till end of the first HELLO
Por supuesto, con una entrada más simple podría usar una palabra más pequeña, o tal vez incluso un solo carácter.
HTH!
sed
¡Y todos los otros sabores de expresiones regulares!
Encontrar la primera aparición de una expresión:
POSIX ERE (usando la opción -r
)
Regex:
(EXPRESSION).*|.
Sed:
sed -r "s/(EXPRESSION).*|./\1/g" # Global `g` modifier should be on
Ejemplo (encontrar la primera secuencia de dígitos) Demostración en vivo :
$ sed -r "s/([0-9]+).*|./\1/g" <<< "foo 12 bar 34"
12
¿Cómo funciona ?
Esta expresión regex se beneficia de una alternancia |
. En cada posición, el motor buscará el primer lado de la alternancia (nuestro objective) y si no coincide con el segundo lado de la alternancia que tiene un punto .
coincide con el siguiente personaje inmediato.
Como se establece el indicador global, el motor intenta continuar emparejando carácter por carácter hasta el final de la cadena de entrada o nuestro objective. Tan pronto como coincida el primer y único grupo de captura del lado izquierdo de la alternancia (EXPRESSION)
rest de la línea también se consumirá inmediatamente .*
. Ahora mantenemos nuestro valor en el primer grupo de captura.
POSIX BRE
Regex:
\(\(\(EXPRESSION\).*\)*.\)*
Sed:
sed "s/\(\(\(EXPRESSION\).*\)*.\)*/\3/"
Ejemplo (encontrar la primera secuencia de dígitos):
$ sed "s/\(\(\([0-9]\{1,\}\).*\)*.\)*/\3/" <<< "foo 12 bar 34"
12
Esta es como la versión ERE pero sin alternancia. Eso es todo. En cada motor de posición individual intenta hacer coincidir un dígito.
Si se encuentra, los otros dígitos siguientes se consumen y se capturan y el rest de la línea se empareja inmediatamente de lo contrario, ya que *
significa más o cero , salta sobre el segundo grupo de captura \(\([0-9]\{1,\}\).*\)*
y llega a un punto .
para unir un solo personaje y este proceso continúa.
Encontrar la primera aparición de una expresión delimitada :
Este enfoque coincidirá con la primera aparición de una cadena que está delimitada. Podemos llamarlo un bloque de cuerda.
sed "s/\(END-DELIMITER-EXPRESSION\).*/\1/; \ s/\(\(START-DELIMITER-EXPRESSION.*\)*.\)*/\1/g"
Cadena de entrada:
foobar start block #1 end barfoo start block #2 end
-EDE: end
-SDE: start
$ sed "s/\(end\).*/\1/; s/\(\(start.*\)*.\)*/\1/g"
Salida:
start block #1 end
Primero, regex \(end\).*
Coincide y captura el extremo del delimitador del primer end
y sustituye todos los caracteres recientes capturados que es el delimitador final. En esta etapa, nuestra salida es: foobar start block #1 end
.
Luego, el resultado pasa a la segunda expresión regular \(\(start.*\)*.\)*
Que es igual a la versión POSIX BRE anterior. Coincide con un solo carácter si el inicio del delimitador de start
no coincide, de lo contrario coincide y captura el delimitador de inicio y coincide con el rest de los caracteres.
Usando el enfoque n. ° 2 (expresión delimitada) debe seleccionar dos expresiones apropiadas:
EDE: [^:/]\/
SDE: http:
Uso:
$ sed "s/\([^:/]\/\).*/\1/g; s/\(\(http:.*\)*.\)*/\1/" <<< "http://www.suepearson.co.uk/product/174/71/3816/"
Salida:
http://www.suepearson.co.uk/
Esto se puede hacer usando corte:
echo "http://www.suepearson.co.uk/product/174/71/3816/" | cut -d'/' -f1-3
sed – juego no codicioso por Christoph Sieghart
El truco para obtener coincidencias no codiciosas en sed es hacer coincidir todos los caracteres, excluyendo el que termina el partido. Lo sé, una obviedad, pero perdí unos minutos preciosos y los guiones de shell deberían ser, después de todo, rápidos y fáciles. Entonces, en caso de que alguien más lo necesite:
Engaño codicioso
% echo "foobar" | sed 's/<.*>//g' bar
Juego no codicioso
% echo "foobar" | sed 's/<[^>]*>//g' foobar
Otra forma, sin usar regex, es usar el método de campo / delimitador, por ej.
string="http://www.suepearson.co.uk/product/174/71/3816/" echo $string | awk -F"/" '{print $1,$2,$3}' OFS="/"
sed
ciertamente tiene su lugar, ¡pero este no es uno de ellos!
Como Dee ha señalado: solo usa cut
. Es mucho más simple y mucho más seguro en este caso. Aquí hay un ejemplo donde extraemos varios componentes de la URL usando la syntax de 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-)
te dio:
protocol = "http" host = "www.suepearson.co.uk" urlhost = "http://www.suepearson.co.uk" urlpath = "product/174/71/3816/"
Como puede ver, este es un enfoque mucho más flexible.
(todo crédito a Dee)
sed 's|(http:\/\/[^\/]+\/).*|\1|'
sed -E interpreta expresiones regulares como expresiones regulares extendidas (modernas)
Actualización: -E en MacOS X, -r en GNU sed.
Todavía hay esperanza de resolver esto usando sed puro (GNU). A pesar de que esto no es una solución genérica, en algunos casos puede usar “bucles” para eliminar todas las partes innecesarias de la cadena como esta:
sed -r -e ":loop" -e 's|(http://.+)/.*|\1|' -e "t loop"
El único problema aquí es que también cortará el último carácter separador (‘/’), pero si realmente lo necesita, puede simplemente volver a colocarlo después de que termine el “bucle”, solo agregue este comando adicional al final del anterior línea de comando:
-e "s,$,/,"
Como usted indicó específicamente que está tratando de usar sed (en lugar de perl, corte, etc.), intente agrupar. Esto evita que el identificador no codicioso no sea reconocido. El primer grupo es el protocolo (es decir, ‘http: //’, ‘https: //’, ‘tcp: //’, etc.). El segundo grupo es el dominio:
echo "http://www.suon.co.uk/product/1/7/3/" | sed "s | ^ \ (. * // \) \ ([^ /] * \). * $ | \ 1 \ 2 |"
Si no está familiarizado con la agrupación, comience aquí .
Me doy cuenta de que esta es una entrada antigua, pero a alguien le puede resultar útil. Como el nombre de dominio completo no puede exceder una longitud total de 253 caracteres, reemplace. * Con. \ {1, 255 \}
echo "/home/one/two/three/myfile.txt" | sed 's|\(.*\)/.*|\1|'
no te molestes, lo tengo en otro foro 🙂
sed 's|\(http:\/\/www\.[az.0-9]*\/\).*|\1|
funciona también
Otra versión sed:
sed 's|/[:alphanum:].*||' file.txt
Concuerda /
seguido por un carácter alfanumérico (por lo tanto, no otra barra inclinada), así como el rest de los caracteres hasta el final de la línea. Luego lo reemplaza con nada (es decir, lo elimina).
Aquí hay algo que puedes hacer con un enfoque de dos pasos y awk:
A=http://www.suepearson.co.uk/product/174/71/3816/ echo $A|awk ' { var=gensub(///,"||",3,$0) ; sub(/\|\|.*/,"",var); print var }'
Salida: http://www.suepearson.co.uk
¡Espero que ayude!
Esta es la forma robusta de hacer correspondencias no codiciosas de cadenas de caracteres múltiples usando sed. Digamos que quieres cambiar cada foo...bar
a
así que por ejemplo esta entrada:
$ cat file ABC foo DEF bar GHI foo KLM bar NOP foo QRS bar TUV
debería convertirse en este resultado:
ABC GHI NOP TUV
Para hacer eso, convierte foo y barra en caracteres individuales y luego usa la negación de esos caracteres entre ellos:
$ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/<&>/g; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file ABC GHI NOP TUV
En lo de arriba:
s/@/@A/g; s/{/@B/g; s/}/@C/g
s/@/@A/g; s/{/@B/g; s/}/@C/g
está convirtiendo {
y }
en cadenas de marcador de posición que no pueden existir en la entrada, por lo que esos caracteres están disponibles para convertir foo
y bar
en. s/foo/{/g; s/bar/}/g
s/foo/{/g; s/bar/}/g
está convirtiendo foo
y bar
en {
y }
respectivamente s/{[^{}]*}/<&>/g
está realizando el op que queremos – convirtiendo foo...bar
en
s/}/bar/g; s/{/foo/g
s/}/bar/g; s/{/foo/g
está convirtiendo {
y }
nuevo a foo
y bar
. s/@C/}/g; s/@B/{/g; s/@A/@/g
s/@C/}/g; s/@B/{/g; s/@A/@/g
está convirtiendo las cadenas de marcador de posición a sus caracteres originales. Tenga en cuenta que lo anterior no se basa en ninguna cadena en particular que no esté presente en la entrada, ya que fabrica dichas cadenas en el primer paso, ni le importa qué ocurrencia de alguna expresión regular particular que quiera emparejar, ya que puede usar {[^{}]*}
tantas veces como sea necesario en la expresión para aislar la coincidencia real que desea y / o con el operador de coincidencia numérica de seds, por ejemplo, para reemplazar solo la segunda ocurrencia:
$ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/<&>/2; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file ABC foo DEF bar GHI NOP foo QRS bar TUV