Estou tentando usar o sed para limpar linhas de URLs para extrair apenas o domínio.
Então de:
http://www.suepearson.co.uk/product/174/71/3816/
Eu quero:
http://www.suepearson.co.uk/
(com ou sem a barra à direita, não importa)
Eu tentei:
sed 's|\(http:\/\/.*?\/\).*|\1|'
e (escapando do quantificador não ganancioso)
sed 's|\(http:\/\/.*\?\/\).*|\1|'
mas não consigo fazer com que o quantificador não ganancioso ( ?
) funcione, portanto ele sempre corresponde à seqüência inteira.
sed -E 's...
. Ainda assim, nenhum operador relutante.cut -d'/' -f1-3
funciona simples .Respostas:
Nem o Regex Posix / GNU básico nem estendido reconhece o quantificador não ganancioso; você precisa de uma regex posterior. Felizmente, o regex Perl para esse contexto é muito fácil de obter:
fonte
-pi -e
.perl
é exigido pelo POSIXsed
, usando uma sintaxe basicamente idêntico ao desed
Nesse caso específico, você pode fazer o trabalho sem usar uma regex não gananciosa.
Experimente este regex não ganancioso em
[^/]*
vez de.*?
:fonte
([^&=#]+)=([^&#]*)
. Existem casos que não funcionam dessa maneira com certeza, por exemplo, ao analisar o URL da parte do host e do nome do caminho com a barra final considerada opcional, excluída da captura:^(http:\/\/.+?)/?$
Com o sed, eu geralmente implemento uma pesquisa não gananciosa procurando qualquer coisa, exceto o separador até o separador:
Resultado:
isto é:
-n
s/<pattern>/<replace>/p
;
separador de comandos de pesquisa em vez de/
facilitar a digitação,s;<pattern>;<replace>;p
\(
...\)
, mais tarde acessível com\1
,\2
...http://
[]
,[ab/]
significaria tantoa
oub
ou/
^
em[]
meiosnot
, então seguido por qualquer coisa, menos a coisa no[]
[^/]
significa qualquer coisa, exceto/
caráter*
é repetir o grupo anterior, o que[^/]*
significa caracteres, exceto/
.sed -n 's;\(http://[^/]*\)
significa pesquisar e lembrarhttp://
seguido por qualquer caractere, exceto/
e lembrar o que você encontrou/
e adicionar outro/
no final:sed -n 's;\(http://[^/]*\)/'
mas queremos corresponder ao restante da linha após o domínio, para adicionar.*
\1
) é o domínio, substitua a linha correspondente pelas coisas salvas no grupo\1
e imprima:sed -n 's;\(http://[^/]*\)/.*;\1;p'
Se você deseja incluir barra invertida também após o domínio, adicione mais uma barra invertida no grupo para lembrar:
resultado:
fonte
O sed não suporta o operador "não ganancioso".
Você precisa usar o operador "[]" para excluir "/" da correspondência.
PS: não há necessidade de barra invertida "/".
fonte
s/([[:digit:]]\.[[1-9]]*)0*/\1/
obviamente não funcionaria bem1.20300
. Como a pergunta original era sobre URLs, eles deveriam ser mencionados na resposta aceita.Simulando um quantificador preguiçoso (não guloso) no
sed
E todos os outros sabores de regex!
Localizando a primeira ocorrência de uma expressão:
POSIX ERE (usando a
-r
opção)Regex:
Sed:
Exemplo (localizando a primeira sequência de dígitos) Demonstração ao vivo :
Como isso funciona ?
Esse regex se beneficia de uma alternância
|
. Em cada posição, o mecanismo tenta escolher a correspondência mais longa (este é um padrão POSIX que também é seguido por outros dois mecanismos), o que significa que continua.
até que uma correspondência seja encontrada([0-9]+).*
. Mas a ordem também é importante.Como o sinalizador global está definido, o mecanismo tenta continuar correspondendo caractere por caractere até o final da string de entrada ou nosso destino. Assim que o primeiro e único grupo de captura do lado esquerdo da alternância for correspondido, o
(EXPRESSION)
restante da linha também será consumido imediatamente.*
. Agora mantemos nosso valor no primeiro grupo de captura.POSIX BRE
Regex:
Sed:
Exemplo (localizando a primeira sequência de dígitos):
Este é como a versão ERE, mas sem alternância envolvida. Isso é tudo. Em cada posição única, o mecanismo tenta corresponder a um dígito.
Se for encontrado, outros dígitos a seguir serão consumidos e capturados e o restante da linha corresponderá imediatamente, caso contrário,
*
significa que mais ou zero pula sobre o segundo grupo de captura\(\([0-9]\{1,\}\).*\)*
e chega a um ponto.
para corresponder a um único caractere e esse processo continua.Localizando a primeira ocorrência de um delimitado expressão :
Essa abordagem corresponderá à primeira ocorrência de uma sequência delimitada. Podemos chamá-lo de um bloco de string.
String de entrada:
-EDE:
end
-SDE:
start
Resultado:
O primeiro regex
\(end\).*
corresponde e captura o primeiro delimitador finalend
e substitui todos com caracteres capturados recentes, que é o delimitador final. Nesta fase, a nossa saída é:foobar start block #1 end
.Em seguida, o resultado é passado para o segundo regex
\(\(start.*\)*.\)*
igual à versão POSIX BRE acima. Ele corresponde a um único caractere se o delimitador inicialstart
não for correspondido, caso contrário ele corresponderá e captura o delimitador inicial e o restante dos caracteres.Respondendo diretamente à sua pergunta
Usando a abordagem nº 2 (expressão delimitada), você deve selecionar duas expressões apropriadas:
EDE:
[^:/]\/
SDE:
http:
Uso:
Resultado:
Nota: isso não funcionará com delimitadores idênticos.
fonte
sed
todos os outros mecanismos que seguem a mesma ordem padrão , importa quando se trata de igualdade. Portantoecho 'foo 1' | sed -r 's/.|([0-9]+).*/\1/g'
, não tem correspondência, masecho 'foo 1' | sed -r 's/([0-9]+).*|./\1/g'
sim.Solução não gananciosa para mais de um único caractere
Este tópico é realmente antigo, mas eu suponho que as pessoas ainda precisem. Digamos que você queira matar tudo até a primeira ocorrência de
HELLO
. Você não pode dizer[^HELLO]
...Portanto, uma boa solução envolve duas etapas, supondo que você possa poupar uma palavra única que não está esperando na entrada, digamos
top_sekrit
.Nesse caso, podemos:
Obviamente, com uma entrada mais simples, você poderia usar uma palavra menor, ou talvez até um único caractere.
HTH!
fonte
`
, eu usaria<$$>
(já que se$$
expande para o ID do processo no shell, embora você precise usar aspas duplas em vez de aspas simples, e isso pode quebrar outras partes do seu regex) ou, se o unicode estiver disponível, algo como<∈∋>
.perl
oupython
ou algum outro idioma.perl
faz isso de uma maneira menos frágil em uma única linha ...sed - correspondência não gananciosa de Christoph Sieghart
O truque para obter uma correspondência não gananciosa no sed é corresponder a todos os caracteres, exceto aquele que termina a correspondência. Eu sei, um acéfalo, mas desperdicei minutos preciosos e os scripts de shell devem ser, afinal, rápidos e fáceis. Portanto, caso alguém mais precise:
Correspondência gananciosa
Correspondência não gananciosa
fonte
Isso pode ser feito usando o cut:
fonte
outra maneira, não usando regex, é usar o método de campos / delimitadores, por exemplo
fonte
sed
certamente tem o seu lugar, mas este não é um deles!Como Dee apontou: Basta usar
cut
. É muito mais simples e muito mais seguro nesse caso. Aqui está um exemplo em que extraímos vários componentes da URL usando a sintaxe do Bash:da-te:
Como você pode ver, essa é uma abordagem muito mais flexível.
(todo o crédito para Dee)
fonte
fonte
sed -E interpreta expressões regulares como expressões regulares estendidas (modernas)
Atualização: -E no MacOS X, -r no GNU sed.
fonte
-E
é exclusivo do BSDsed
e, portanto, do OS X. Links para páginas de manual.-r
traz expressões regulares estendidas para o GNU,sed
conforme observado na correção de @ stephancheg. Cuidado ao usar um comando de variabilidade conhecida nas distribuições 'nix. Eu aprendi isso da pior maneira.-r
opção GNU sed apenas altera as regras de escape, de acordo comAppendix A Extended regular expressions
o arquivo de informações e alguns testes rápidos; ele realmente não adicionar um qualificador não ganancioso (a partir deGNU sed version 4.2.1
, pelo menos.)-E
como uma opção não documentada por um tempo, mas na versão 4.2.2.177 , a documentação foi atualizada para refletir isso, o que-E
é bom para os dois agora.Ainda há esperança de resolver isso usando puro (GNU) sed. Apesar de essa não ser uma solução genérica, em alguns casos, você pode usar "loops" para eliminar todas as partes desnecessárias da string como esta:
O único problema aqui é que ele também cortará o último caractere separador ('/'), mas se você realmente precisar, pode simplesmente colocá-lo de volta depois que o "loop" terminar, basta acrescentar este comando adicional no final do anterior linha de comando:
fonte
Como você declarou especificamente que está tentando usar sed (em vez de perl, cut, etc.), tente agrupar. Isso evita que o identificador não ganancioso potencialmente não seja reconhecido. O primeiro grupo é o protocolo (ou seja, 'http: //', 'https: //', 'tcp: //', etc). O segundo grupo é o domínio:
Se você não está familiarizado com o agrupamento, comece aqui .
fonte
Sei que essa é uma entrada antiga, mas alguém pode achar útil. Como o nome completo do domínio não pode exceder um comprimento total de 253 caracteres, substitua. * Por. \ {1, 255 \}
fonte
É assim que se faz uma correspondência não gananciosa de seqüências de caracteres múltiplos usando sed. Digamos que você queira alterar todos os itens
foo...bar
para<foo...bar>
, por exemplo, esta entrada:deve se tornar esta saída:
Para fazer isso, você converte foo e barra em caracteres individuais e, em seguida, use a negação desses caracteres entre eles:
No exemplo acima:
s/@/@A/g; s/{/@B/g; s/}/@C/g
está convertendo{
e}
em seqüências de espaço reservado que não podem existir na entrada, para que esses caracteres estejam disponíveis para conversãofoo
ebar
para.s/foo/{/g; s/bar/}/g
está convertendofoo
ebar
para{
e}
respectivamentes/{[^{}]*}/<&>/g
está realizando a operação que queremos - convertendofoo...bar
para<foo...bar>
s/}/bar/g; s/{/foo/g
está convertendo{
e de}
volta parafoo
ebar
.s/@C/}/g; s/@B/{/g; s/@A/@/g
está convertendo as seqüências de caracteres do espaço reservado em seus caracteres originais.Observe que o acima exposto não depende de nenhuma string em particular não estar presente na entrada, pois ela fabrica essas strings na primeira etapa, nem se importa com a ocorrência de qualquer regexp em particular que você deseja corresponder, pois você pode usar
{[^{}]*}
quantas vezes for necessário. na expressão para isolar a correspondência real desejada e / ou com o operador de correspondência numérica seds, por exemplo, para substituir apenas a 2ª ocorrência:fonte
Ainda não vi essa resposta, então veja como você pode fazer isso com
vi
ouvim
:Isso executa a
vi
:%s
substituição globalmente (a direitag
), evita gerar um erro se o padrão não for encontrado (e
) e salva as alterações resultantes no disco e sai. Os&>/dev/null
impede a GUI a partir brevemente piscando na tela, que pode ser irritante.Eu gosto de usar
vi
algumas vezes para regexes super-complicado, porque (1) perl émortomorte, (2) vim tem um muito motor regex avançado, e (3) Eu já estou intimamente familiarizado comvi
expressões regulares na minha edição de uso do dia-a-dia documentos.fonte
não se preocupe, eu o comprei em outro fórum :)
fonte
/home/one/two/three/
, se você adicionar outro/
como/home/one/two/three/four/myfile.txt
você vai avidamente corresponderfour
bem:/home/one/two/three/four
, a pergunta é sobre não-gananciosossed 's|\(http:\/\/www\.[a-z.0-9]*\/\).*|\1|
funciona tambémfonte
Aqui está algo que você pode fazer com uma abordagem em duas etapas e o awk:
Espero que ajude!
fonte
Outra versão sed:
Corresponde
/
seguido por um caractere alfanumérico (não outra barra), assim como o restante dos caracteres até o final da linha. Depois, o substitui por nada (ou seja, exclui-o.)fonte
"[[:alnum:]]"
, não"[:alphanum:]"
.