Diferença entre cat e '' para zerar um arquivo

21

Esses dois comandos são diferentes em como eles executam o zeramento de arquivos? Este último é um modo mais curto de fazer o primeiro? O que está acontecendo nos bastidores?

Ambos

$ cat /dev/null > file.txt

$ > file.txt 

rendimento

-rw-r--r--  1 user  wheel  0 May 18 10:33 file.txt
    
por KM. 19.05.2014 / 16:38

5 respostas

27

cat /dev/null > file.txt é um uso inútil do gato .

Basicamente cat /dev/null simplesmente resulta em cat sem nada. Sim funciona, mas é desaprovado por muitos porque resulta em invocar um processo externo que não é necessário.
É uma daquelas coisas que é comum simplesmente porque é comum.

Usar apenas > file.txt funcionará na maioria dos shells, mas não é totalmente portátil. Se você quiser totalmente portátil, as seguintes alternativas são boas:

true > file.txt
: > file.txt

O : e o true não geram dados e são internos do shell (enquanto cat é um utilitário externo), portanto, são mais leves e mais 'adequados'.

Atualização:

Como tylerl mencionou em seu comentário, há também a sintaxe >| file.txt .

A maioria dos shells tem uma configuração que os impedirá de truncar um arquivo existente via > . Você deve usar >| . Isso é para evitar erros humanos quando você realmente quis acrescentar com >> . Você pode ativar o comportamento com set -C .

Então, com isso, acho que o método mais simples, mais adequado e portátil de truncar um arquivo seria:

:>| file.txt
    
por 19.05.2014 / 16:44
20

Em termos de portabilidade:

                      Bourne POSIX  zsh    csh/tcsh  rc/es  fish
> file                Y      Y      N(1)   N(1)      N      N
: > file              N/Y(2) Y(3)   Y      Y(4)      N(5)   N(5)
true > file           Y(5)   Y      Y      Y(5)      Y(5)   Y(5)
cat /dev/null > file  Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
eval > file           Y(3,8) Y(3)   Y      Y(6)      Y      Y
cp /dev/null file (7) Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
printf '' > file      Y(5)   Y      Y      Y(5)      Y(5)   Y

Notas:

  1. exceto em sh ou ksh emulation, para redirecionamentos sem um comando, em zsh, é assumido um comando padrão (um pager para redirecionamento de stdin apenas, cat caso contrário), que pode ser ajustado com o NULLCMD e Variáveis READNULLCMD. Isso é inspirado no recurso semelhante em (t)csh
  2. Inicialmente, os redirecionamentos não eram executados para : no UnixV7, pois : foi interpretado na metade do caminho entre um líder de comentário e um comando nulo. Mais tarde eles foram e como para todos os builtins, se o redirecionamento falhar, que sai do shell.
  3. : e eval sendo built-ins especiais, se o redirecionamento falhar, que sai do shell ( bash apenas faz isso no modo POSIX).
  4. Curiosamente, em (t)csh , isso está definindo um rótulo nulo (para goto ), então goto '' lá seria ramificado lá. Se o redirecionamento falhar, isso sai do shell.
  5. A menos que / se o comando correspondente esteja disponível em $PATH ( : geralmente não é; true , cat , cp e printf geralmente são (POSIX exige)).
  6. Se o redirecionamento falhar, isso sai do shell.
  7. Se file for um link simbólico para um arquivo não existente, no entanto, algumas implementações de cp como o GNU recusarão criá-lo.
  8. As versões iniciais do shell Bourne não suportavam o redirecionamento de builtins embora

Em termos de legibilidade:

(esta seção é altamente subjetiva)

  • %código%. Esse > file parece muito com um prompt ou um comentário. Além disso, a pergunta que vou fazer ao ler isso (e a maioria dos shells irá reclamar sobre o mesmo) é qual saída exatamente você está redirecionando? .
  • %código%. > é conhecido como o comando no-op. Então, isso é imediatamente interpretado como gerar um arquivo vazio. No entanto, aqui novamente, que : > file pode ser facilmente perdido e / ou visto como um prompt.
  • : : o que booleano tem a ver com redirecionamento ou conteúdo de arquivo? O que se entende aqui? é a primeira coisa que me vem à mente quando li isso.
  • %código%. Concatenar : em true > file ? cat /dev/null > file sendo frequentemente visto como o comando para descarregar o conteúdo do arquivo, que ainda pode fazer sentido: despejar o conteúdo de o arquivo vazio em /dev/null , um pouco como uma maneira complicada de dizer file , mas ainda compreensível.
  • %código%. Copia o conteúdo do arquivo vazio para cat . Faz sentido, embora alguém que não saiba como o file deve fazer por padrão pense que você está tentando fazer o cp /dev/null file a cp /dev/null file device também.
  • file ou cp . Não executa nada e redireciona sua saída para um file . Faz sentido para mim. Estranho que não seja uma expressão comum.
  • null : explicitamente imprime nada em um arquivo. Aquele que faz mais sentido para mim.

Em termos de desempenho

A diferença será se estamos usando um shell embutido ou não. Se não, um processo tem que ser bifurcado, o comando é carregado e executado.

eval > file é garantido para ser construído em todos os shells. eval '' > file é embutido onde quer que esteja disponível (gosta de Bourne / csh). file está embutido apenas em shells semelhantes a Bourne.

printf '' > file está embutido nos mais modernos shells semelhantes a Bourne e eval .

: e true geralmente não são internos.

Agora, printf não invoca redirecionamentos de shell, então coisas como:

find . -exec cp /dev/null {} \;

será mais eficiente que:

find . -exec sh -c '> "$1"' sh {} \;

(embora não necessariamente que:

find . -exec sh -c 'for f do : > "$f"; done' sh {} +

).

Pessoalmente

Pessoalmente, eu uso fish em shells parecidos com o Bourne, e não uso nada além de shells parecidos com o Bourne atualmente.

    
por 19.05.2014 / 23:01
5

Você pode querer olhar para truncate , que faz exatamente isso: truncar um arquivo.

Por exemplo:

truncate --size 0 file.txt

Isso provavelmente é mais lento do que usar true > file.txt .

Meu ponto principal, no entanto, é: truncate é destinado a truncar arquivos, enquanto estiver usando > tem o efeito colateral de truncar um arquivo.

    
por 19.05.2014 / 16:54
1

A resposta depende um pouco do que file.txt é, e como o processo escreve para ela!

Vou citar um caso de uso comum: você tem um arquivo de log crescente chamado file.txt e deseja rotacioná-lo.

Portanto, copie, por exemplo, file.txt para file.txt.save e trunque file.txt .

Neste cenário, SE o arquivo não é aberto por another_process (ex: another_process poderia ser um programa que envia para esse arquivo, por exemplo, um programa registrando algo), então seu 2 propostas são equivalentes, e ambos funcionam bem (mas o segundo é preferido como o primeiro "cat / dev / null > file.txt" é um Useless Use of Cat e também abre e lê / dev / null).

Mas o problema real seria se o other_process ainda estivesse ativo e ainda tivesse um identificador aberto indo para o arquivo.txt.

Em seguida, surgem dois casos principais, dependendo de como other process abriu o arquivo:

  • Se other_process abrir do modo normal, o identificador continuará apontando para o local anterior no arquivo, por exemplo, no deslocamento de 1.200 bytes. A próxima gravação, portanto, começará no deslocamento 1200 e, assim, você terá novamente um arquivo de 1200 bytes (+ o que quer que seja que o other_process escreveu), com 1200 caracteres nulos à esquerda! Não é o que você quer , eu presumo.

  • Se other_process abriu file.txt em "modo de acréscimo", então, toda vez que ele for escrito, o ponteiro procurará ativamente até o final do arquivo. Portanto, quando você truncar, ele irá "buscar" até o byte 0, e você não terá o efeito colateral ruim! Isto é o que você quer (... normalmente!)

Observe que isso significa que você precisa truncar um arquivo para garantir que todos os other_process que estão gravando nesse local o tenham aberto no modo "anexar". Caso contrário, você precisará parar os other_process e iniciá-los novamente, para que eles comecem a apontar para o início do arquivo, em vez do local anterior.

Referências: link para obter uma explicação mais clara, e um pequeno exemplo de diferença entre o registro em modo normal e de anexação em < href="https://stackoverflow.com/a/984761/1841533"> link

    
por 19.05.2014 / 18:21
1

Eu gosto disso e o uso frequentemente porque ele parece mais limpo e não como se alguém acertasse a tecla return acidentalmente:

echo -n "" > file.txt

Deve ser um built-in também?

    
por 19.05.2014 / 20:30