Normalmente, cat /dev/null > [something]
quando você deseja limpar o conteúdo do arquivo, assegura um risco zero de interrupção no estado real do arquivo. O conteúdo do arquivo será limpo com clareza, cat /dev/null
mas o arquivo em si - como existe e é conhecido pelo sistema de arquivos em que reside - ainda estará lá com o mesmo número de inode, propriedade e permissões.
No caso de um arquivo de log, pode ser que o próprio arquivo de log esteja marcado como "em uso" por outro processo. Fazer isso, por exemplo, rm /var/log/messages && touch /var/log/messages
seria prejudicial a outros processos e poderia causar o sufocamento dos processos em execução. Significando que um processo que de alguma forma está bloqueado para um número de inode específico conectado ao arquivo /var/log/messages
pode entrar em pânico repentinamente e dizer: “Ei! O que aconteceu com /var/log/messages
! ”Mesmo se o arquivo ainda estiver lá. Sem mencionar possíveis problemas com a propriedade e as permissões sendo recriadas incorretamente.
Devido a esta incerteza no uso / estado de um arquivo o uso de cat /dev/null > [something]
é o preferido pelos administradores de sistema que querem limpar um log, mas não querem potencialmente interferir com o funcionamento dos processos já existentes.
Além disso, no contexto da página que você vincula ao autor, declara o seguinte:
Não há nada incomum aqui, apenas um conjunto de comandos que poderiam ser facilmente invocados um a um a partir da linha de comando no console ou em uma janela do terminal. As vantagens de colocar os comandos em um script vão muito além de não ter que digitá-los novamente.
Portanto, o “nada de incomum” que o autor menciona diz respeito a todo o conceito do que é esse script bash específico: é apenas um conjunto de comandos simples que podem ser executados com facilidade na linha de comando, mas são colocados em um arquivo de texto para evite ter que digitá-los repetidamente.
truncate -s 0
faria a mesma coisa e seria menos idiomático. No entanto, os programadores de shell são um grupo conservador e pode-se encontrar sistemas com idade suficiente ou maluco o suficiente para não ter esse comando.cat /dev/null > /foo/bar
trunca o arquivo;echo "" > /foo/bar
trunca e, em seguida, grava um único caractere de nova linha.Você fará isso para truncar o conteúdo de um arquivo enquanto mantém o inode intacto. Todos os programas que possuem esse arquivo aberto para leitura ou gravação não seriam afetados fora do fato de que o tamanho do arquivo seria redefinido para zero.
Uma alternativa falsa frequentemente encontrada é remover o arquivo e criá-lo novamente:
ou similar:
O problema é que esses métodos não impedem que o arquivo antigo seja mantido gravado por quaisquer processos que tenham o arquivo excluído aberto no momento da exclusão. A razão pela qual está em sistemas de arquivos Unix, quando você exclui um arquivo, você desvincula apenas o nome (caminho) do conteúdo (inode). O inode é mantido ativo enquanto houver processos abertos para leitura ou gravação.
Isso leva a vários efeitos negativos: os logs gravados após a exclusão do arquivo são perdidos, pois não há uma maneira simples / portátil de abrir um arquivo excluído. Enquanto um processo está gravando no arquivo excluído, seu conteúdo ainda está usando espaço no sistema de arquivos. Isso significa que, se você remover / criar o arquivo porque estava preenchendo seu disco, ele permanecerá preenchido. Uma maneira de corrigir esse último problema é reiniciar os processos do criador de logs, mas talvez você não queira fazer isso para serviços críticos e os logs intermediários seriam definitivamente perdidos. Também existem efeitos colaterais, porque o arquivo que você cria pode não ter as mesmas permissões, proprietário e grupo que o original. Isso, por exemplo, pode impedir que um analisador de logs leia o arquivo recém-criado ou, pior ainda, evite que o processo de log grave seus próprios logs.
O primeiro método,
cat /dev/null > file
atingir o objetivo corretamente , no entanto, apesar de uma lenda urbana tenaz, suacat /dev/null
parte não faz absolutamente nada útil. Ele abre um pseudo arquivo vazio por design, não consegue ler nada dele e, finalmente, sai. O uso desse comando é um desperdício de pressionamentos de tecla, bytes, chamadas de sistema e ciclos de CPU e pode ser substituído sem nenhuma alteração funcional pelo comando no-op, sem dúvida, mais rápido:
ou mesmo, com a maioria dos shells, por nenhum comando.Deixe-me tentar uma metáfora para explicar como
cat /dev/null
é inútil . Digamos que seu objetivo é esvaziar um copo.Você primeiro remove qualquer líquido dele. Isso é suficiente e é precisamente o que (
> file
) faz, pois os redirecionamentos são sempre processados primeiro.Depois, você escolhe uma garrafa vazia (
/dev/null
) e despeja no copo vazio (cat
). Este é o passo inútil ...Se você ler o documento vinculado até o final, poderá observar os comentários nesta linha na versão aprimorada do script:
Eles realmente têm; muito ruim
cat /dev/null
foi mantido no código.Isso significa que o código a seguir funcionará com todos os shells comuns (ambos
csh
esh
famílias):e isso vai funcionar com todas as conchas usando a sintaxe Bourne, como
ash
,bash
,ksh
,zsh
e os gostos:Observe, no entanto, que com shells antigos Bourne pré-POSIX, qualquer um desses comandos, inclusive
cat /dev/null
, não truncará um arquivo se ele for gravado posteriormente por um script de shell ainda em execução anexado a ele. Em vez de um arquivo de zero byte, seria um arquivo esparso com seu tamanho inalterado. O mesmo aconteceria se o arquivo fosse gravado por um processo buscando a posição que ele pensa ser a atual antes de ser gravada.Observe também que algumas soluções alternativas frequentemente sugeridas para truncar um arquivo têm falhas.
Ambos os seguintes simplesmente não fazem o trabalho. O arquivo resultante não está vazio, mas contém uma linha vazia. Isso quebraria arquivos de log como
wtmp
esse que armazenam registros de largura fixa.A próxima baseada em uma
sh
opção BSD não é portátil, o POSIX não especifica nenhuma opção permitida para eco, portanto, você pode acabar com um arquivo contendo uma linha com "-n
":Esse também não é portátil, usando uma
sh
sequência de escape do System V. Alguns shells criarão um arquivo contendo uma linha com "\c
":Esse usa um comando projetado para fazer o trabalho. O problema usado
truncate
não é portátil, pois esse comando, não sendo especificado pelo POSIX, pode estar ausente em um sistema Unix / Linux.Finalmente, aqui estão algumas alternativas que são portáteis e farão o trabalho corretamente:
Imprimindo explicitamente uma sequência vazia no arquivo:
Usando o
true
comando que é estritamente equivalente ao no-op,:
embora mais legível:fonte
csh
implementações atuais, embora não esteja necessariamente documentado. Nacsh
página de manual do Solaris: Null command. This command is interpreted, but performs no action.
. Não encontrei menção do mesmo natcsh
página do manual ou no original do BSDcsh
, mas essa sintaxe sempre funcionou.cat /dev/null
é explicitar suas intenções./dev/null
uma maneira eficiente de injetar zero bytes, de qualquer maneira mais confiável do que usar:
ou nada. Nesta mesma página, a resposta de Cyrus, que era concisa, mas direta ao ponto, tinha zero voto, enquanto a de JakeGould, que estava contestando o fato,cat /dev/null
era um no-op (veja nossos comentários) já tinha pelo menos quatro votos.>
ou:
não é clara. Concordo que é uma pena que os mitos tenham sido propagados devido ao seu uso.printf "" > file
que é portátil (POSIX) e leve, tão frequentemente implementado quanto um shell embutido.É uma maneira complicada de colocar o arquivo em tamanho zero.
fonte
csh
.: > messages
também funciona.:
outrue
são as opções mais óbvias para comandos que não imprimem nada e retornam verdadeiros.Para truncar um arquivo aberto. Isso é equivalente e mais compreensível:
(Adicionado -n para evitar a nova linha)
fonte
wtmp
caso. Veja minha resposta atualizada.bash
,-n
não é garantido que funcione em todos os reservatórios Bourne.