Tento manter as últimas 50 linhas no meu arquivo, onde salvo a temperatura a cada minuto. Eu usei este comando:
tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test
Mas o resultado é um arquivo de teste vazio. Eu pensei, ele lista as últimas 50 linhas do arquivo de teste e o insere no arquivo de teste. Quando eu uso este comando:
tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2
está funcionando bem. Existem 50 linhas no arquivo test2.
Alguém pode me explicar onde está o problema?
command-line
logs
tail
dorinand
fonte
fonte
logging
módulo #Respostas:
O problema é que seu shell está configurando o pipeline de comandos antes de executar os comandos. Não é uma questão de "entrada e saída", é que o conteúdo do arquivo já desapareceu antes mesmo da execução da cauda. É algo como:
>
arquivo de saída para gravação, truncando-otail
.tail
corre, abre/home/pi/Documents/test
e não encontra nada láExistem várias soluções, mas a chave é entender o problema, o que realmente está errado e o porquê.
Isso produzirá o que você está procurando,
Explicação:
$()
é chamado substituição de comando que executatail -n 50 /home/pi/Documents/test
> /home/pi/Documents/test
redireciona a saídaecho "$(tail -n 50 /home/pi/Documents/test)"
para o mesmo arquivo.fonte
bash: xrealloc: cannot allocate 18446744071562067968 bytes
Outra solução para o redirecionamento de arquivo que limpa primeiro o arquivo é usar a
sponge
partir domoreutils
pacote assim:fonte
Isso ocorre porque o bash processa o redirecionamento com o
>
primeiro, excluindo o conteúdo do arquivo. Em seguida, ele executa o comando. Se você usasse>>
, as últimas 50 linhas seriam anexadas ao final do que está atualmente no arquivo. Nesse caso, você teria as mesmas 50 linhas repetidas duas vezes.O comando funciona conforme o esperado ao redirecionar para um arquivo diferente. Aqui está uma maneira de gravar as últimas 50 linhas de um arquivo em um arquivo com o mesmo nome:
Isso primeiro grava as últimas 50 linhas em um arquivo temporário, que é movido usando-se
mv
para substituir o arquivo original.Conforme observado nos comentários, isso não funcionará se o arquivo ainda estiver aberto. Mover o arquivo também cria um novo inode e pode alterar a propriedade e as permissões. Uma maneira melhor de fazer isso usando um arquivo temporário seria:
O arquivo temporário também pode ser removido, embora cada vez que isso aconteça, seu conteúdo seja sobrescrito.
fonte
tail -50 /home/pi/Documents/test >/tmp/foo && cat /tmp/foo >/home/pi/Documents/test
tail ... > temp ; cat temp > orig ; rm -f temp
trabalho.Como você viu o principal problema do redirecionamento de shell, eis uma maneira alternativa de remover um arquivo das últimas 50 linhas:
O trabalho árduo é feito pelo (GNU) sed com o
-i
recurso "edição no local", que funciona sob os bastidores criando a saída em um arquivo temporário. O restante das linhas configurou a matemática para a operação do sed, a saber:wc
) e subtraia 50; atribuir isso an
.n
for positivo, execute o comando sed para excluir as linhas 1 a n.fonte
printf
é usado para canalizar comandos (um por linha)ed
. Osed
comandos são:1,$-50d
- excluir todas as últimas 50 linhas, exceto as últimasw
- escreve o arquivo modificado de volta ao discoComo não há redirecionamentos envolvidos, o shell não pode sobrescrever o arquivo de saída antes de ser lido.
Além disso, ao contrário da maioria das formas de edição "no local" (que normalmente simula a edição "no local", criando um arquivo temporário e renomeá-lo sobre o original),
ed
na verdade , edita o arquivo original - para manter o mesmo inode ( e proprietário, grupo e permissões - tempfile + mv sempre alterará o inode e poderá alterar os outros, dependendo das circunstâncias).fonte
Em uma faixa um pouco diferente, você pode usar
logrotate(8)
o backup regularmente dos arquivos de log em arquivos nomeados de forma incremental e excluir os antigos.É assim que os principais arquivos de log do sistema são gerenciados para impedir que eles cresçam demais.
fonte