Eu tenho um arquivo com cerca de 1000 linhas. Quero a parte do meu arquivo após a linha que corresponde à minha declaração grep.
Isso é:
$ cat file | grep 'TERMINATE' # It is found on line 534
Então, quero o arquivo da linha 535 à linha 1000 para processamento adicional.
Como eu posso fazer isso?
grep 'TERMINATE' file
grep
a interface de entrada padrão da s para ler dados, em vez de ter que aprender em que opção aplicargrep
, esed
, eawk
, epandoc
, e, effmpeg
etc. quando queremos ler de um arquivo. Isso economiza tempo, porque não precisamos aprender uma nova opção toda vez que queremos fazer a mesma coisa: ler de um arquivo.grep 'TERMINATE' < file
. Talvez ele faz tornar a leitura um pouco mais difícil - mas isto é shell script, de modo que é sempre vai ser um problema :)Respostas:
A seguir, imprimirá a linha correspondente
TERMINATE
até o final do arquivo:Explicado:
-n
desativa o comportamento padrãosed
de imprimir cada linha depois de executar seu script,-e
indicar um script parased
,/TERMINATE/,$
é uma seleção de intervalo de endereço (linha), o que significa que a primeira linha corresponde àTERMINATE
expressão regular (como grep) no final do arquivo ($
) , ep
é o comando de impressão que imprime a linha atual.Isso será impresso a partir da linha que segue a linha correspondente
TERMINATE
até o final do arquivo:(de APÓS a linha correspondente a EOF, NÃO incluindo a linha correspondente)
Explicado:
1,/TERMINATE/
é uma seleção de faixa de endereço (linha) que significa a primeira linha da entrada da 1ª linha correspondente àTERMINATE
expressão regular ed
é o comando delete que exclui a linha atual e pula para a próxima linha. Comosed
o comportamento padrão é imprimir as linhas, ele imprimirá as linhas apósTERMINATE
o final da entrada.Editar:
Se você deseja as linhas antes
TERMINATE
:E se você deseja as duas linhas antes e depois
TERMINATE
em 2 arquivos diferentes em uma única passagem:Os arquivos antes e depois conterão a linha com terminação, para processar cada um que você precisa usar:
Edit2:
Se você não desejar codificar os nomes de arquivos no script sed, poderá:
Mas então você precisa escapar do
$
significado da última linha para que o shell não tente expandir a$w
variável (observe que agora usamos aspas duplas ao redor do script em vez de aspas simples).Esqueci de dizer que a nova linha é importante após os nomes dos arquivos no script, para que o sed saiba que os nomes dos arquivos terminam.
Edição: 2016-0530
Sébastien Clément perguntou: "Como você substituiria o código fixo
TERMINATE
por uma variável?"Você faria uma variável para o texto correspondente e, em seguida, faria da mesma maneira que no exemplo anterior:
para usar uma variável para o texto correspondente com os exemplos anteriores:
Os pontos importantes sobre a substituição de texto por variáveis nesses casos são:
$variablename
) incluídas emsingle quotes
['
] não serão "expandidas", mas variáveis dentro dedouble quotes
["
] serão. Portanto, você deve alterar todos ossingle quotes
paradouble quotes
se eles contiverem texto que você deseja substituir por uma variável.sed
faixas também conter um$
e são imediatamente seguidos por uma letra como:$p
,$d
,$w
. Eles também irá olhar como variáveis a serem expandidas, então você tem que escapar esses$
caracteres com uma barra invertida [\
] como:\$p
,\$d
,\$w
.fonte
sed -e "1,/$matchtext/d"
não funciona quando$matchtext
ocorre na primeira linha. Eu tive que mudar isso parased -e "0,/$matchtext/d"
.Como uma aproximação simples, você pode usar
que cumprimenta
TERMINATE
e gera até 100000 linhas após essa linha.Da página do manual
fonte
file
:grep -A$(cat file | wc -l) TERMINATE file
Uma ferramenta para usar aqui é awk:
Como é que isso funciona:
As outras soluções podem consumir muita memória se você as usar em arquivos muito grandes.
fonte
cat file | awk 'BEGIN{ found=0} /###/{found=found+1} {if (found<2) print }'
cat
.awk
é perfeitamente capaz de usar um ou mais nomes de arquivos como argumentos. Veja também stackoverflow.com/questions/11710552/useless-use-of-catSe entendi sua pergunta corretamente, você deseja as linhas depois
TERMINATE
, sem incluir aTERMINATE
linha.awk
pode fazer isso de uma maneira simples:Explicação:
if(found) print
) não imprimirá nada para começar.Isso imprimirá todas as linhas após a
TERMINATE
linha.Generalização:
Exemplo:
Explicação:
found
estiver definida.found=1
para que as seguintes linhas sejam impressas. Observe que essa verificação é feita após a impressão real para excluir a linha de partida do resultado.Notas:
BEGIN{found=0}
ao início da expressão awk.fonte
{if(found) print}
é um pouco antipadrão no awk, é mais idiomático substituir o bloco por apenasfound
oufound;
se você precisar de outro filtro posteriormente.awk '{if(found) print} /TERMINATE/{found=1}' your_file
porawk 'found; /TERMINATE/{found=1}' your_file
, ambos devem fazer a mesma coisa.Use a expansão de parâmetros do bash como a seguir:
fonte
printf
ou garantir que sabe exatamente para o que está passandoecho
.).grep -Um arquivo 10000000 'TERMINATE'
fonte
Existem várias maneiras de fazer isso com
sed
ouawk
:Isso procura
TERMINATE
no seu arquivo e é impresso a partir dessa linha até o final do arquivo.Esse é exatamente o mesmo comportamento que
sed
.Caso você saiba o número da linha a partir da qual deseja iniciar a impressão, é possível especificá-la juntamente com
NR
(número do registro, que eventualmente indica o número da linha):Exemplo
fonte
more +7 file
Se, por qualquer motivo, você desejar evitar o uso do sed, o seguinte imprimirá a linha correspondente
TERMINATE
até o final do arquivo:e o seguinte será impresso a partir da seguinte linha correspondente
TERMINATE
até o final do arquivo:São necessários dois processos para fazer o que o sed pode fazer em um processo e, se o arquivo mudar entre a execução do grep e do tail, o resultado pode ser incoerente, por isso recomendo o uso do sed. Além disso, se o arquivo não contiver
TERMINATE
, o 1º comando falhará.fonte
Alternativas à excelente
sed
resposta de jfgagne e que não incluem a linha correspondente:awk '/TERMINATE/ {y=1;next} y'
( https://stackoverflow.com/a/18166628 )awk '/TERMINATE/ ? c++ : c'
( https://stackoverflow.com/a/23984891 )perl -ne 'print unless 1 .. /TERMINATE/'
( https://stackoverflow.com/a/18167194 )fonte
Esta poderia ser uma maneira de fazê-lo. Se você souber qual linha do arquivo possui sua palavra grep e quantas linhas possui no seu arquivo:
grep -A466 'TERMINATE' arquivo
fonte
grep
nem será necessário; você pode simplesmente usartail -n $NUM
, então isso não é realmente uma resposta.sed é uma ferramenta muito melhor para o trabalho: sed -n '/ re /, $ p' file
onde re é regexp.
Outra opção é o sinalizador - após o contexto do grep. Você precisa passar um número para finalizar, usando wc no arquivo deve fornecer o valor certo para parar em. Combine isso com -n e sua expressão de correspondência.
fonte
Eles imprimirão todas as linhas da última linha encontrada "TERMINATE" até o final do arquivo:
fonte
grep
para que você possa alimentá-lotail
é um antipadrão de desperdício. A localização da correspondência e a impressão até o final do arquivo (ou, inversamente, a impressão e a parada na primeira correspondência) são eminentemente realizadas com as próprias ferramentas regulares e essenciais de regex. O massivogrep | tail | sed | awk
também é, por si só, um uso inútil egrep
massivo de amigos .tail
e execute a tarefa na ferramenta mais capaz. De qualquer forma, o título diz claramente "primeira partida".