Por que você iria 'cat / dev / null / var / log / messages'?

75

Nesta página de exemplo do script 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ê cat /dev/null em alguma coisa? Não consigo entender o que é pretendido aqui (é como usar while TRUE; sleep 1; elihw para {some busy program} ?). No entanto, o autor chama isso de "Nada incomum".

    
por isomorphismes 06.12.2014 / 20:40

4 respostas

39

Você normalmente usa cat /dev/null > [something] quando deseja limpar o conteúdo do arquivo, garantindo que não há risco zero de interrupção do estado real do arquivo. O conteúdo do arquivo será claramente apagado pelo cat /dev/null , mas o próprio arquivo - como existe e é conhecido pelo sistema de arquivos no qual ele 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. Assim, por exemplo, um rm /var/log/messages && touch /var/log/messages seria prejudicial para outros processos e poderia fazer com que os processos em execução fossem sufocados. O que significa que um processo que de alguma forma está bloqueado para um número de inode específico conectado ao arquivo /var/log/messages pode de repente entrar em pânico e dizer: “Ei! O que aconteceu com /var/log/messages ! ", Mesmo que o arquivo ainda esteja lá. Sem mencionar possíveis problemas com propriedade e permissões sendo recriados incorretamente.

Devido a essa incerteza no uso / estado de um arquivo, o uso de cat /dev/null > [something] é preferido pelos administradores do sistema que desejam limpar um log, mas não querem potencialmente interferir com a operação de processos já existentes.

Além disso, no contexto da página que você vincula , o autor afirma o seguinte:

There is nothing unusual here, only a set of commands that could just as easily have been invoked one by one from the command-line on the console or in a terminal window. The advantages of placing the commands in a script go far beyond not having to retype them time and again.

Portanto, o "nada incomum" que o autor menciona é com relação a todo o conceito do que é esse script bash específico: é apenas um conjunto de comandos simples que podem ser executados facilmente a partir da linha de comando, mas colocados em um arquivo de texto para evitar ter que redigitá-los repetidamente.

    
por 06.12.2014 / 20:50
120

Why would you cat /dev/null onto anything?

Você fará isso para truncar o conteúdo de um arquivo enquanto mantém o inode intacto. Todos os programas que têm esse arquivo aberto para leitura ou gravação não seriam afetados fora do fato de que o tamanho do arquivo seria zerado.

Uma alternativa falsa 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 gravado por qualquer processo que tenha o arquivo excluído aberto no momento da exclusão. A razão pela qual está sob sistemas de arquivos Unix, quando você exclui um arquivo, você apenas desvincula seu nome (caminho) de seu conteúdo (inode). O inode é mantido vivo enquanto houver processos que o abrem para leitura ou escrita.

Isso leva a vários efeitos negativos: os logs escritos após a exclusão do arquivo são perdidos, pois não há uma maneira direta / portátil de abrir um arquivo excluído. Enquanto um processo estiver gravando no arquivo excluído, seu conteúdo ainda estará usando espaço no sistema de arquivos. Isso significa que, se você remover / criar o arquivo porque ele estava preenchendo o disco, o disco ficará cheio. Uma maneira de corrigir este último problema é reiniciar os processos do registrador, mas você pode não querer fazer isso para serviços críticos e logs intermediários seriam definitivamente perdidos. Há também efeitos colaterais devido ao fato de que o arquivo que você cria pode não ter as mesmas permissões, proprietário e grupo do que o original. Isso, por exemplo, pode impedir que um analisador de logs leia o arquivo recém-criado ou, pior, impedir que o processo de registro grave seus próprios registros.

O primeiro método, cat /dev/null > file atinge o objetivo corretamente no entanto, apesar de uma lenda urbana tenaz, sua cat /dev/null parte não faz absolutamente nada útil. Ele abre um pseudo arquivo que é vazio por design, falha em ler qualquer coisa e finalmente sai. Usar esse comando é um desperdício de pressionamentos de teclas, bytes, chamadas do sistema e ciclos de CPU, e pode ser substituído sem qualquer alteração funcional pelo comando sem operação mais rápido : ou mesmo, com a maioria dos shells, sem comando algum .

Deixe-me tentar uma metáfora para explicar o quanto cat /dev/null é inútil. Digamos que seu objetivo seja esvaziar um copo.

  • Primeiro remova qualquer líquido dela. Isso é suficiente e é precisamente o que ( > file ) faz, já que os redirecionamentos são sempre processados primeiro.

  • Depois, você escolhe uma garrafa vazia ( /dev/null ) e despeja-a no copo vazio ( cat ). Este é o passo inútil ...

Se você ler seu documento vinculado até o final, talvez perceba os comentários neste linha da versão aprimorada do script:

    cat /dev/null > wtmp  #  ': > wtmp' and '> wtmp'  have the same effect.

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 ( csh e sh families):

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

e isso funcionará com todos os shells usando a sintaxe Bourne, como ash , bash , ksh , zsh e os gostos:

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

No entanto, com antigos shells pré-POSIX Bourne, qualquer um desses comandos, incluindo cat /dev/null , não truncará um arquivo se for escrito posteriormente por um shell script ainda em execução anexado a ele. Em vez de um arquivo de zero bytes, isso seria um arquivo esparso com seu tamanho inalterado. O mesmo aconteceria se o arquivo fosse escrito por um processo buscando a posição que ele acha que é a atual antes de escrever.

Tenha também em atenção que algumas soluções alternativas sugeridas para truncar um ficheiro apresentam 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 que armazenam registros de largura fixa.

    echo > file
    echo "" > file
    
  • O próximo baseado em uma opção BSD sh não é portátil, POSIX não especifica nenhuma opção permitida para echo, então você pode acabar com um arquivo contendo uma linha com " -n ":

    echo -n > file
    
  • Esse não é portátil usando uma seqüência de escape do System V sh . Algumas shells criarão um arquivo contendo uma linha com " \c ":

    echo "\c" > file
    
  • Esse usa um comando projetado para fazer o trabalho. O problema é usar truncate não é portável porque este comando, não sendo especificado pelo POSIX, pode estar faltando em um sistema Unix / Linux.

    truncate -s 0
    

Por fim, aqui estão algumas alternativas que são portáteis e que farão o trabalho corretamente:

  • Explicitamente imprimindo uma string vazia para o arquivo:

    printf "" > file
    
  • Usando o comando true , que é estritamente equivalente ao não-operado, um : , embora seja mais legível:

    true > file
    
por 06.12.2014 / 22:24
6

É uma maneira complicada de levar o arquivo ao tamanho zero.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
    
por 06.12.2014 / 20:44
-2

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

echo -n > /var/log/messages

(Adicionado -n para evitar a nova linha)

    
por 07.12.2014 / 19:29

Tags