Preciso remover repetidamente a primeira linha de um arquivo de texto enorme usando um script bash.
No momento eu estou usando sed -i -e "1d" $FILE
- mas leva cerca de um minuto para fazer a exclusão.
Existe uma maneira mais eficiente de conseguir isso?
Respostas:
Tente cauda :
-n x
: Basta imprimir as últimasx
linhas.tail -n 5
daria as últimas 5 linhas da entrada. O+
sinal meio que inverte o argumento e torna atail
impressão qualquer coisa, menos as primeirasx-1
linhas.tail -n +1
imprimiria o arquivo inteiro,tail -n +2
tudo menos a primeira linha etc.GNU
tail
é muito mais rápido quesed
.tail
também está disponível no BSD e o-n +2
sinalizador é consistente nas duas ferramentas. Verifique as páginas de manual do FreeBSD ou OS X para mais.A versão BSD pode ser muito mais lenta do
sed
que isso. Eu me pergunto como eles conseguiram isso;tail
deve apenas ler um arquivo linha por linha enquantosed
realiza operações bastante complexas que envolvem a interpretação de um script, a aplicação de expressões regulares e similares.Nota: Você pode ficar tentado a usar
mas isso lhe dará um arquivo vazio . O motivo é que o redirecionamento (
>
) acontece antestail
é chamado pelo shell:$FILE
tail
tail
processo para$FILE
tail
lê a partir do agora vazio$FILE
Se você deseja remover a primeira linha dentro do arquivo, você deve usar:
O
&&
irá certificar-se de que o arquivo não obter substituído quando há um problema.fonte
-r
opção Talvez haja uma configuração de buffer em algum lugar do sistema? Ou-n
é um número assinado de 32 bits?tail
funcionará para qualquer tamanho de arquivo.-n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
Você pode usar -i para atualizar o arquivo sem usar o operador '>'. O comando a seguir excluirá a primeira linha do arquivo e salvará no arquivo.
fonte
unterminated transform source string
sed -i '1,2d' filename
tail -n +2
. Não sei por que não é a melhor resposta.Para aqueles que estão no SunOS que não é GNU, o seguinte código ajudará:
fonte
Não, isso é tão eficiente quanto você conseguirá. Você poderia escrever um programa em C que pudesse fazer o trabalho um pouco mais rápido (menos tempo de inicialização e argumentos de processamento), mas provavelmente tenderá à mesma velocidade que o sed, à medida que os arquivos aumentam (e suponho que sejam grandes se demorar um minuto )
Mas sua pergunta sofre do mesmo problema que tantas outras, pois pressupõe a solução. Se você nos disser em detalhes o que está tentando fazer, então como , podemos sugerir uma opção melhor.
Por exemplo, se esse é um arquivo A que outro programa B processa, uma solução seria não retirar a primeira linha, mas modificar o programa B para processá-lo de maneira diferente.
Digamos que todos os seus programas anexem a esse arquivo A e o programa B atualmente lê e processa a primeira linha antes de excluí-lo.
Você pode reprojetar o programa B para que ele não tente excluir a primeira linha, mas mantenha um deslocamento persistente (provavelmente baseado em arquivo) no arquivo A, para que, da próxima vez que seja executado, ele possa procurar esse deslocamento, processo a linha lá e atualize o deslocamento.
Então, em um horário silencioso (meia-noite?), Ele poderia executar um processamento especial do arquivo A para excluir todas as linhas processadas no momento e definir o deslocamento de volta para 0.
Certamente será mais rápido para um programa abrir e buscar um arquivo, em vez de abrir e reescrever. Esta discussão assume que você tem controle sobre o programa B, é claro. Não sei se é esse o caso, mas pode haver outras soluções possíveis se você fornecer mais informações.
fonte
awk FNR-1 *.csv
provavelmente é mais rápido.Você pode editar os arquivos no local: Basta usar o
-i
sinalizador do perl , assim:Isso faz a primeira linha desaparecer, como você pede. O Perl precisará ler e copiar o arquivo inteiro, mas organiza para que a saída seja salva com o nome do arquivo original.
fonte
Você pode fazer isso facilmente com:
na linha de comando; ou para remover a primeira linha de um arquivo permanentemente, use o modo local de sed com o
-i
sinalizador:fonte
Como Pax disse, você provavelmente não vai ficar mais rápido que isso. O motivo é que quase não existem sistemas de arquivos que suportem truncamento desde o início do arquivo, portanto esta será uma
n
operação O ( ) em quen
é o tamanho do arquivo. O que você pode fazer muito mais rápido é sobrescrever a primeira linha com o mesmo número de bytes (talvez com espaços ou um comentário) que pode funcionar para você, dependendo exatamente do que você está tentando fazer (o que é isso, a propósito?).fonte
O
sponge
utilitário evita a necessidade de manipular um arquivo temporário:fonte
sponge
é de fato muito mais limpo e mais robusta do que a solução aceite (tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
)sponge
buffer todo o arquivo está na memória? Isso não funcionará se forem centenas de GB.sponge
o absorverá, pois ele usa um arquivo / tmp como uma etapa intermediária, que é usada para substituir o original posteriormente.Se você quiser modificar o arquivo no lugar, você pode sempre usar o original
ed
em vez do seu s sucessor treamingsed
:O
ed
comando era o editor de texto UNIX original, antes mesmo de existirem terminais de tela cheia, muito menos estações de trabalho gráficas. Oex
editor, mais conhecido como o que você está usando quando digitação no prompt do cólon emvi
, é um ex versão tendia deed
, por isso, muitos dos mesmos comandos de trabalho. Emboraed
seja para ser usado interativamente, também pode ser usado no modo em lote enviando uma sequência de comandos para ele, que é o que esta solução faz.A seqüência
<<<$'1d\nwq\n'
tira proveito do apoio do Bash para cadeias de caracteres here (<<<
) e citações POSIX ($'
...'
) à entrada de alimentação para oed
comando que consiste em duas linhas:1d
, que d eletes linha 1 , e, em seguidawq
, que w ritos o arquivo de volta para disco e, em seguida, q sai da sessão de edição.fonte
deve mostrar as linhas, exceto a primeira linha:
fonte
Pode usar o vim para fazer isso:
Isso deve ser mais rápido, pois o vim não lê o arquivo inteiro durante o processo.
fonte
+wq!
se o seu shell é bash. Provavelmente não, já que a!
palavra não está no começo de uma palavra, mas adquirir o hábito de citar as coisas provavelmente é bom. (E se você está buscando supereficiência sem citar desnecessariamente, também não precisa de aspas1d
).Que tal usar o csplit?
fonte
csplit file /^.*$/1
. Ou, mais simplesmente:csplit file //1
. Ou ainda mais simples:csplit file 2
.Como parece que não posso acelerar a exclusão, acho que uma boa abordagem pode ser processar o arquivo em lotes como este:
A desvantagem disso é que, se o programa for morto no meio (ou se houver algum sql ruim lá - causando a morte ou o bloqueio da parte "processo"), haverá linhas que serão ignoradas ou processadas duas vezes .
(arquivo1 contém linhas de código sql)
fonte
Se o que você está procurando é se recuperar após a falha, basta criar um arquivo com o que você fez até agora.
fonte
Este liner fará:
Funciona, já que
tail
é executado antesecho
e depois o arquivo é desbloqueado, portanto, não há necessidade de um arquivo temporário.fonte
Usar cauda em linhas N-1 e direcioná-lo para um arquivo, seguido pela remoção do arquivo antigo e renomear o novo arquivo para o nome antigo, faria o trabalho?
Se eu estivesse fazendo isso de maneira programática, leria o arquivo e lembre-se do deslocamento do arquivo, depois de ler cada linha, para que eu pudesse procurar novamente nessa posição para ler o arquivo com menos uma linha.
fonte