Como posso excluir tudo até um padrão e tudo após outro padrão de uma linha?


16

No seguinte arquivo:

Lorem ipsum dolor sente-se no meio, consectetuer adipiscing elit. Ut eu metus id lectus vestibulum ultrices. Mecenas rhoncus.

Quero excluir tudo antes consectetuere depois elit.

Minha saída desejada:

consectetuer adipiscing elit.

Como posso fazer isso?


2
O comando pode ser sed. Também pode ser perl, ou até pura festa.
Muru

@manuel Se uma dessas respostas resolver seu problema, reserve um momento e aceite-o clicando na marca de seleção à esquerda. Isso marcará a pergunta como respondida e é assim que os agradecimentos são expressos nos sites do Stack Exchange.
terdon

Respostas:


27

Eu usaria sed

sed 's/^.*\(consectetuer.*elit\).*$/\1/' file

Decodificou o sed s / find / replace / syntax:

  • s/^.*- substituto começando no início da linha ( ^) seguido por qualquer coisa ( .*) até ...
  • \( - inicia um bloco nomeado
  • consectetuer.*elit\.- corresponda à primeira palavra, tudo ( .*) até a última palavra (neste caso, incluindo o ponto final (escapado)) que você deseja corresponder
  • \) - finalize o bloco nomeado
  • corresponde a todo o resto ( .*) até o final da linha ( $)
  • / - finalize a seção de localização substituta
  • \1- substitua pelo bloco de nome entre o \(e o \)acima
  • / - finalize a substituição

1
Boa resposta, mas você não precisa do ^ou, $já que o sed tentará encontrar a correspondência mais longa. Além disso, você pode ter perdido o ponto depois elit, pode inserir \.se necessário.
Asoundmove 17/11

2
@asoundmove Boa captura do ponto à direita em "elit". - você tem um olho muito aguçado! Atualizei minha resposta para incluir o ponto de escape no padrão. Seu também correto que o ^e $não são necessárias - Deixei-os lá para que o entrevistador observou (originalmente) que ele foi um pouco de um novato e esta pode ser útil em outros contextos.
Mikev

Sempre copiei as soluções sed e as cortei para atender às minhas necessidades, mas, graças a esta resposta, sinto que realmente as compreendo agora. Ótima resposta
Tyler

6

Se todas as linhas contiverem padrão inicial e final, é a maneira mais fácil de fazer isso grep. Em vez de excluir o início e o final de cada linha, você pode simplesmente exibir o conteúdo entre os dois padrões. A -oopção no GNU grepgera apenas as correspondências:

grep -o 'consectetuer.*elit' file

Nota: como mencionado, isso só funciona se todas as linhas no arquivo puderem ser analisadas dessa maneira. Então, novamente, isso representa 80% de todos os casos de uso típicos.


1

Dois para loops no AWK:

$ awk '{for(i=1;i<=NF;i++) {if ($i == "consectetuer") beginning=i; if($i== "elit.") ending=i }; for (j=beginning;j<=ending;j++) printf $j" ";printf "\n"   }' file.txt 
consectetuer adipiscing elit.

Gsub do AWK:

$ awk '{gsub(/^.*consectetuer/,"consectetuer"); gsub(/elit.*$/,"elit.");print}' file.txt
consectetuer adipiscing elit.

1

Um jeito Perl. Isto é essencialmente o mesmo que ased resposta de MikeV :

perl -pe 's/.*(consectetuer.*elit).*./$1/' file

O -pmeio "imprime todas as linhas após aplicar o script fornecido com -e". O s/foo/bar/é o operador de substituição; ele será substituído foopor bar. Os parênteses capturam um padrão e vamos usá-lo na substituição. O primeiro padrão capturado é $1o segundo $2e assim por diante.

Portanto, o comando corresponderá tudo até consectetuer( .*consectetuer), tudo até elit( .*elit) e todo o resto até o final da linha ( .*) e o substituirá pelo padrão capturado.


1

Não sei por que esse título da pergunta foi editado " do arquivo " para " de uma linha ", enquanto o OP não exclui a possibilidade em várias linhas, mesmo que o exemplo pareça ser apenas uma linha. Seja como for, pode ser útil fornecer uma solução de várias linhas aqui.

Isso funciona para linhas cruzadas:

from1=consectetuer; to2=elit; a="$(cat file)"; a="$(echo "${a#*"$from1"}")"; echo "$from1${a%%"$to2"*}$to2"

Exemplos:

[xiaobai@xiaobai tmp]$ cat file
1
abc consectetuer lsl

home

def elit dd
2 consectetuer ABC elit
[xiaobai@xiaobai tmp]$ from1=consectetuer; to2=elit; a="$(cat file)"; a="$(echo "${a#*"$from1"}")"; echo "$from1${a%%"$to2"*}$to2"
consectetuer lsl

home

def elit
[xiaobai@xiaobai tmp]$ 

Referência: Expansão de Parâmetro do Shell


1
Perfeito!
Clément
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.