grep --before-context 5
mostra 5 linhas antes da partida.
Eu quero mostrar tudo antes da partida.
Fazer grep --before-context 99999999
funcionaria, mas não é muito ... profissional.
Como mostrar todo o arquivo até a partida?
grep --before-context 5
mostra 5 linhas antes da partida.
Eu quero mostrar tudo antes da partida.
Fazer grep --before-context 99999999
funcionaria, mas não é muito ... profissional.
Como mostrar todo o arquivo até a partida?
Respostas:
Sed é melhor para isso.
Apenas faça:
sed '/PATTERN/q' FILE
Funciona assim:
Para cada linha, verificamos se corresponde /PATTERN
:
Esta é a solução mais eficiente, porque assim que vê PATTERN
, sai. Sem q
, o sed continuaria lendo o restante do arquivo e não faria nada com ele. Para arquivos grandes, isso pode fazer a diferença.
Este truque também pode ser usado para emular head
:
sed 10q FILE
sed '/PATTERN/Q' FILE
pula a linha correspondente. Q
é uma extensão GNU, portanto não funcionará com nenhum sed.
sed
pode substituir a maioria das funcionalidades do grep.
sed -n '1,/<pattern>/ p' <file>
Isso significa imprimir da primeira linha até o padrão ser correspondido.
Alguns exemplos de intervalo
sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2
imprima até e inclua a correspondência:
awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename
imprima até, mas NÃO incluindo a correspondência:
awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename
Q
o afaik legal, mas específico do GNU, sed -n '/pattern/!p;//q'
seria mais portátil.
!
que p
aplica-se a linhas que não correspondem pattern
, mas isso //q
me confunde ...
//
significa "expressão regular anterior" (eu pensei que isso significava "corresponder à string vazia"). Eu acho que uma versão mais curta da mesma solução é sed -n '/pattern/q;p
:?
Os seguintes grep
métodos GNU puros não são eficientes.
Pesquise tudo, até a primeira instância da string " foo " na barra de arquivos , usando três grep
s:
grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar
Correspondendo até a última instância de " foo ":
grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar
Nota: detalhes sobre o último grep
podem ser encontrados em: Regex (grep) para pesquisa em várias linhas necessária .
grep
s (+ pcre) quando se trata de simplesmente executar uma única sed
invocação: sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'
??
sed
código parece ter sua própria resposta ou pode ser adicionado a um dos outros. Re 7 grep
s: Como não houve grep
resposta ... (além disso, a resposta ajuda a mostrar por que não.) #
Adicionando à resposta de Mikel acima ...
Para imprimir todas as linhas até, mas não incluindo , a primeira linha que FILE
contém PATTERN
, tente:
sed '/.*PATTERN.*/{s///;q;}' FILE
Isso corresponde à linha inteira que contém o padrão, substitui-o por uma linha em branco e sai sem processar o restante do arquivo.
Pós-script:
A maneira mais fácil / clara de evitar a impressão de uma nova linha extra no final (sem envolver outra ferramenta), era executar o sed novamente e excluir a nova linha final:
sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'
... e como agora estamos excluindo essa linha de qualquer maneira, nosso trabalho anterior é redundante e podemos simplificar:
sed '/PATTERN/q' FILE | sed '$d'
sed
invocação.
tcsh
e um bash
apelido, eu precisava me certificar de que tinha uma solução de linha única relativamente concisa que funcionava tanto no padrão quanto no GNU sed
(para portabilidade); todos os requisitos que sua contribuição pode muito bem ter cumprido. Como alguém que usa sed
muito raramente, meu requisito mais importante era algo que eu pudesse entender rapidamente quando quiser editar ou redirecioná-lo facilmente daqui a alguns anos.
Para pessoas que optam por se lembrar apenas das ferramentas básicas do dia-a-dia e dispostas a aceitar soluções menos elegantes e menos eficientes:
head -n $(grep -n pattern filename | cut -d: -f1) filename
Se esse comando for para um script, procurarei soluções mais elegantes (e possivelmente eficientes). Se esse é um comando único ou um script descartável, não me importo.
Você também pode usar um dos seguintes
tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac
ou
tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac
ou
tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac
A primeira opção é muito semelhante à sugerida pelo OP, mas garante que você mostre linhas suficientes antes do contexto, contando as linhas no arquivo
A segunda opção pesquisa o número da linha da primeira correspondência (você também pode alterar isso alterando a 'cabeça' interna) e depois usa a cabeça nesse número
A última opção substitui todas as novas linhas pela correspondência e, em seguida, substitui duas correspondências adjacentes por uma nova linha. A saída disso é uma linha para cada bloco de texto entre duas correspondências. Depois disso, ele usa 'head' para escolher a primeira linha (mantendo o bloco de texto até a primeira correspondência) correspondente e depois traduz novamente cada correspondência para uma nova linha. essa opção funciona apenas se o arquivo estiver no seguinte formato
pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern
texttexttext
texttexttexttexttexttexttexttexttext
e assim por diante
sed
comando na parte inferior é meio complicado.