:>filename.txt
Por exemplo:
root@box$ dd if=/dev/zero of=file.txt count=1024 bs=1024
1024+0 records in
1024+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00536175 s, 196 MB/s
root@box$ ll
total 1024
-rw-r--r-- 1 root root 1048576 Nov 15 14:40 file.txt
root@box$ :>file.txt
root@box$ ll
total 0
-rw-r--r-- 1 root root 0 Nov 15 14:40 file.txt
Isso é diferente de um rm
? Ele opera mais rápido ou mais devagar do que outros meios semelhantes de zerar um arquivo ou excluí-lo?
Como você descobriu, isso apenas esvazia o conteúdo do arquivo (trunca o arquivo); que é diferente de
rm
comorm
removeria o arquivo completamente. Além disso,:>file.txt
realmente criará o arquivo se ele ainda não existir.:
é um "comando não fazer nada" que sairá com sucesso e não produzirá saída, portanto, é simplesmente um método curto para esvaziar um arquivo. Na maioria dos shells, você pode simplesmente fazer>file.txt
para obter o mesmo resultado. Também pode ser um pouco mais rápido do que outros métodos, comoecho >file.txt
potencialmenteecho
um comando externo.Além disso,
echo >file.txt
colocaria uma linha em brancofile.txt
onde:>file.txt
faria com que o arquivo não tivesse conteúdo algum.Sim, é diferente de
rm
.rm
removeria o arquivo.:>filename.txt
esvazia o arquivo, deixando-o ainda lá, mas com zero bytes de tamanho.A invocação de shell
>filename.txt
redireciona alguma saída para o arquivo "filename.txt" para substituí-lo completamente. Portanto, o shell precisa limpar todo o conteúdo do arquivo fornecido antes de gravar a saída nele.A saída a ser redirecionada é a saída do comando executado. Curti:
Fará com que o arquivo de nome filename.txt contenha exatamente (e somente) a string
Hello
.Executando:
apagará tudo dentro do arquivo e depois gravará
New Value
nele.Se o comando não tiver saída, como o comando
true
, o arquivo permanecerá vazio (truncado).Um comando que também é um shell embutido é
:
(apenas um ponto duplo (dois pontos)) e que não tem saída. Ser um builtin torna mais rápido do que um comando externo comotrue
(que também não tem saída). Então, ou:removerá todo o conteúdo do arquivo nomeado
filename.txt
ou o criará como um arquivo vazio se não existir.Isso é diferente de um rm, pois um rm fará o arquivo desaparecer de
ls
, não fará com que o arquivo contenha 0 bytes.Novamente, o arquivo não está sendo deletado (desaparece da lista dada por
ls
) ele se transforma em um arquivo vazio (contém 0 bytes).Deve ser mais rápido do que chamar um comando externo para esvaziar um arquivo. Ter que criar um shell filho para carregar o executável e
exec
o comando torna os comandos externos mais lentos que o interno:
.Soluções semelhantes são (algumas definidas
$?
como 1):re: desempenho: isso é o mais eficiente possível no shell; apenas pedir ao kernel para truncar um arquivo existente deve ser mais eficiente do que desvincular o arquivo e recriar um novo inode com o mesmo nome. A menos que você queira que o arquivo seja excluído, nesse caso
rm
ouunlink
ele.:
é um shell embutido, portanto, evita fork/exec. Assim é o equivalentetrue
em conchas modernas normais.>foo
outrue > foo
faz com que o shell trunque o arquivo fazendo umaopen(path, O_WRONLY|O_TRUNC|O_CREAT, 0666)
chamada de sistema.Ou na prática com DASH no Linux, a partir da
strace sh
saída:openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
que é equivalente.Então tem
close()
que voltar a esse FD. Na verdade, o DASH não é um caso especial quando você usa:>
, ele salta pelos seguintes aros:O uso
> foo
no DASH leva à mesma sequência de chamadas do sistema, redirecionando o fd1 e restaurando-o. Eu não verifiqueibash
ou outras conchas.Mas isso ainda é significativamente mais barato do que criar um novo processo para executar
truncate -s 0 foo
que (espero) faria uma únicatruncate("foo", 0)
chamada de sistema que presumivelmente seria ainda mais eficiente que umopen
+close
.De uma linguagem como C (ou qualquer coisa com ligações de chamada do sistema), truncar um arquivo que você não deseja abrir pode ser feito de maneira mais eficiente com uma
truncate
syscall direta.No Dash,
3>foo
leva a esta sequência de chamadas do sistema:Abrir um novo fd resulta em já ser fd 3, evitando qualquer duping. Esta é a maneira mais eficiente no dash, provavelmente economizando vários microssegundos vs.
>foo
. Se isso importa, shell script é a linguagem errada para sua tarefa!! Mas você perguntou.Com a mitigação Spectre+Meltdown habilitada, mesmo uma
-ENOSYS
chamada de sistema ruim leva pelo menos milhares de ciclos de clock, ou seja, microssegundos, no moderno Intel x86-64. Acima de algumas centenas para a viagem de ida e volta usuário->kernel->usuário com apenas umasyscall
instrução. É claro que as pesquisas de caminho e assim por diante levam um tempo significativo, assim como o código do sistema de arquivos. E ir para o modo kernel e voltar muitas vezes despeja algum cache, tornando o espaço do usuário mais lento no retorno.O custo real de E/S uma vez que os metadados fazem write-back no disco depende do sistema de arquivos. Um FS como XFS ou ext4 moderno usando apenas 1 ou algumas extensões grandes para o arquivo inteiro pode liberar facilmente grandes quantidades de espaço em tempo O(1). Ou O(n) onde
n
é o número de extensões (fragmentação) e não o tamanho em bytes.Dependendo do FS, se as informações de extensão foram armazenadas diretamente no inode, em vez de um bloco indireto, isso é uma coisa a menos para adicionar à lista gratuita.
O custo de E/S é semelhante a desvincular o arquivo, mas você não precisa liberar o inode ou modificar a entrada do diretório. Você ainda precisa atualizar o mtime e o ctime no inode após o truncamento, mas você teve que escrevê-lo de qualquer maneira se o tamanho mudasse.