Por que você `cat / dev / null> / var / log / messages`?


77

Nesta página de exemplo de script do bash, o autor apresenta este script:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

Por que você colocaria cat /dev/nullalguma coisa? Não consigo entender o que se pretende aqui (é como usar while TRUE; sleep 1; elihwpara {some busy program}?). No entanto, o autor chama isso de "Nada incomum".

Respostas:


40

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/nullmas 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/messagesseria 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/messagespode 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.


10
@jlliagre A única coisa que é "mantida viva" é o contexto da pergunta, focada em por que o autor original faria isso. Se você tem paixão por dissipar o "mito", poste uma resposta que forneça contexto para o método de codificação do autor original, bem como uma perspectiva de por que você acredita que ele pode ser substituído por outros métodos.
— perfil completo de JakeGould

7
@jlliagre A resposta de Cyrus não aborda a questão central de por que o autor original teria usado esse método nem o raciocínio por trás dele. O tutorial mencionado é bastante antigo e razoavelmente aceito. Não é incorreto nem perpetua uma suposta "lenda urbana". Pelo contrário, é a maneira como uma pessoa codifica versus a maneira como outra pessoa codifica. Tão simples como isso. É uma questão de estilo que não tem impacto negativo na confiabilidade ou no desempenho.
— JakeGould

3
truncate -s 0faria 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.
— Schwern

5
@skift cat /dev/null > /foo/bartrunca o arquivo; echo "" > /foo/bartrunca e, em seguida, grava um único caractere de nova linha.
— David

2
Outra vantagem desse método sobre o rm & touch é que a propriedade e as permissões são mantidas.
— Jjmontes

121

Por que você colocaria / dev / null em algo?

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:

rm file
touch file

ou similar:

mv file file.old
gzip file.old
touch file

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 > fileatingir o objetivo corretamente , no entanto, apesar de uma lenda urbana tenaz, sua cat /dev/nullparte 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:

    cat / dev / null> wtmp #   ':> wtmp' e '> wtmp' têm o mesmo efeito.

Eles realmente têm; muito ruim cat /dev/nullfoi mantido no código.

Isso significa que o código a seguir funcionará com todos os shells comuns (ambos cshe shfamílias):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

e isso vai funcionar com todas as conchas usando a sintaxe Bourne, como ash, bash, ksh, zshe os gostos:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

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 wtmpesse que armazenam registros de largura fixa.

    echo > file
    echo "" > file
  • A próxima baseada em uma shopçã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":

    echo -n > file
  • Esse também não é portátil, usando uma shsequência de escape do System V. Alguns shells criarão um arquivo contendo uma linha com " \c":

    echo "\c" > file
  • Esse usa um comando projetado para fazer o trabalho. O problema usado truncatenão é portátil, pois esse comando, não sendo especificado pelo POSIX, pode estar ausente em um sistema Unix / Linux.

    truncate -s 0

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:

    printf "" > file
  • Usando o truecomando que é estritamente equivalente ao no-op, :embora mais legível:

    true > file

1
@ JonathanLeffler Eu acredito que faz parte de todas as cshimplementações atuais, embora não esteja necessariamente documentado. Na csh página de manual do Solaris : Null command. This command is interpreted, but performs no action.. Não encontrei menção do mesmo na tcshpágina do manual ou no original do BSD csh, mas essa sintaxe sempre funcionou.
— Jlliagre

6
Um dos motivos para escrever cat /dev/nullé explicitar suas intenções.
— Davidmh

1
@ Davididmh Isso seria sensato, mas sua declaração não resiste a verificações de fatos. Eu observei esse idioma de shell por provavelmente algumas décadas. Quando tive a oportunidade de perguntar ao autor o raciocínio por trás disso, sempre tive teorias infundadas sobre o uso de /dev/nulluma 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/nullera um no-op (veja nossos comentários) já tinha pelo menos quatro votos.
— Jlliagre

2
@ jlliagre meu conhecimento do shell é bastante básico, então talvez eu não seja o melhor alvo da população; mas uma nua >ou :não é clara. Concordo que é uma pena que os mitos tenham sido propagados devido ao seu uso.
— Davidmh

4
@ Davididmh Se você realmente quer algo explícito antes do redirecionamento, eu recomendaria o printf "" > fileque é portátil (POSIX) e leve, tão frequentemente implementado quanto um shell embutido.
— Jlliagre

6

É uma maneira complicada de colocar o arquivo em tamanho zero.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

Essa sintaxe não funcionará em todos os shell.
— Reinierpost

2
Corrigir. A pergunta está marcada apenas com "bash".
— Cyrus

@reinierpost Ele funcionará em todas as conchas no estilo Bourne, não é? Não vamos nos preocupar csh.
— Barmar 12/12

: > messagestambém funciona. :ou truesão as opções mais óbvias para comandos que não imprimem nada e retornam verdadeiros.
— Peter Cordes

-3

Para truncar um arquivo aberto. Isso é equivalente e mais compreensível:

echo -n > /var/log/messages

(Adicionado -n para evitar a nova linha)


3
Isso é realmente mais compreensível, mas infelizmente não é equivalente. Ele pode até quebrar funcionalidades como no wtmpcaso. Veja minha resposta atualizada.
— Jlliagre

eco -n evita nova linha.
— Jun

6
De fato, se você tiver certeza de usar bash, -nnão é garantido que funcione em todos os reservatórios Bourne.
— Jlliagre 07/07
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.