Diga uma expressão regex para pular o começo de uma linha antes de combinar

1

Se eu tivesse uma string como 45mb ./aaaa/bbbb/cccc/dddd e eu usasse uma regex como [^\/]*\/ ela corresponderia a 45mb ./aaaa/bbbb/cccc/

Eu só quero que ele corresponda a ./aaaa/bbbb/cccc/ , mas não consigo descobrir como fazer isso.

Eu quero combinar especificamente / encontrar todas as ocorrências de "tudo antes de uma barra inclinada até e incluindo a barra", pois quero usar sed para substituir as correspondências, como no comando sed abaixo, mas sem perder a bit de tamanho de arquivo no início.

sed -e 's/[^\/]*\//--/g

Espero que isso faça algum sentido. Eu tentei olhar para frente / para trás, mas não sei se essa é a solução de regex correta para isso.

    
por Flo Woo 26.07.2013 / 20:01

2 respostas

1

Desde que você esclareceu o que queria em um comentário à resposta de Gnouc, aqui está uma solução:

sed 's|[^ /]*/|--|g'

$ echo '45mb ./aaaa/bbbb/cccc/dddd' | sed 's|[^ /]*/|--|g'
45mb --------dddd

Isso será quebrado se você tiver uma barra final ou se o caminho de arquivo que você está passando contiver espaços. Seria muito fácil escrever algo um pouco mais à prova d'água, mas isso envolveria mais do que uma única linha.

Aqui está uma solução usando grupos de captura:

sed -e 's|\([^ ]* \).*/\(.*\)||'

Estou usando | s como separadores, porque não tenho que me preocupar em escapar das barras (mas eu teria que escapar de | s no padrão). AFAIK sed pode ter praticamente qualquer caractere como separador.

O primeiro grupo de captura \([^ ]* \) corresponde a 'qualquer número de qualquer caractere, exceto um espaço em branco, seguido por um espaço em branco'. O .*/ corresponde a "qualquer número de qualquer caractere, seguido por uma barra invertida", e o segundo grupo \(.*\) captura "qualquer número de qualquer caractere".

As expressões regulares de Sed (e a maioria das expressões regulares) são gananciosas por padrão, então .*/ corresponderá à string mais longa que corresponder ao seu padrão.

$ echo '45mb ./aaaa/bbbb/cccc/dddd' | sed 's|\([^ ]* \).*/\(.*\)||'
45mb dddd

No entanto, isso será interrompido se houver uma barra:

$ echo '45mb ./aaaa/bbbb/cccc/dddd/' | sed 's|\([^ ]* \).*/\(.*\)||'
45mb 

Esta versão irá funcionar mesmo com uma barra final, mas irá quebrar se você tiver mais de uma:

sed -e 's|\([^ ]* \).*/\(.\)||'

$ echo '45mb ./aaaa/bbbb/cccc/dddd/' | sed 's|\([^ ]* \).*/\(.\)||'
45mb dddd/
$ echo '45mb ./aaaa/bbbb/cccc/dddd//' | sed 's|\([^ ]* \).*/\(.\)||'
45mb /
    
por 26.07.2013 / 20:49
0

Aqui está a solução usando regex com perl:

$ echo '45mb ./aaaa/bbbb/cccc/dddd' | perl -ne 'print $1 if /(\.\/.*\/)/'
./aaaa/bbbb/cccc/    

E substituição:

$ echo '45mb ./aaaa/bbbb/cccc/dddd' | perl -ple 's/(\.\/.*\/)/--/'
45mb --dddd
    
por 26.07.2013 / 20:35