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?

manuel
fonte
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
MikeV
fonte
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.

slebetman
fonte
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.
Sergiy Kolodyazhnyy
fonte
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.

terdon
fonte
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

林果 皞
fonte
1
Perfeito!
Clément