Por que redirecionar a saída de um arquivo para ele mesmo produz um arquivo em branco?
Declarado em Bash, por que
less foo.txt > foo.txt
e
fold foo.txt > foo.txt
produzir um vazio foo.txt
? Como um anexo como less eggs.py >> eggs.py
produz duas cópias do texto eggs.py
, pode-se esperar que uma substituição produza uma cópia do texto.
Note, eu não estou dizendo que isso é um bug, é mais provável que seja um ponteiro para algo profundo sobre o Unix.
bash
unix
unix-utils
seewalker
fonte
fonte
Respostas:
Quando você usa
>
, o arquivo é aberto no modo de truncamento para que seu conteúdo seja removido antes que o comando tente lê-lo.Quando você usa
>>
, o arquivo é aberto no modo de acréscimo para que os dados existentes sejam preservados. No entanto, ainda é bastante arriscado usar o mesmo arquivo que entrada e saída nesse caso. Se o arquivo for grande o suficiente para não caber no tamanho do buffer de entrada de leitura, seu tamanho poderá aumentar indefinidamente até que o sistema de arquivos esteja cheio (ou sua cota de disco seja atingida).Se você deseja usar um arquivo como entrada e saída com um comando que não suporta modificação no local, você pode usar algumas soluções alternativas:
Use um arquivo intermediário e substitua o original quando terminar e somente se nenhum erro ocorrer durante a execução do utilitário (esta é a maneira mais segura e mais comum).
Evite o arquivo intermediário à custa de uma potencial perda de dados parcial ou completa, se ocorrer um erro ou interrupção. Neste exemplo, o conteúdo de
foo.txt
é passado como entrada para um subshell (dentro dos parênteses) antes que o arquivo seja excluído. O inode anterior permanece ativo enquanto o subshell o mantém aberto durante a leitura dos dados. O arquivo gravado pelo utilitário interno (aquifold
) com o mesmo nome (foo.txt
) aponta para um inode diferente porque a entrada do diretório antigo foi removida tecnicamente; existem dois "arquivos" diferentes com o mesmo nome durante o processo. Quando o subshell termina, o inode antigo é liberado e seus dados são perdidos. Cuidado para garantir espaço suficiente para armazenar temporariamente o arquivo antigo e o novo ao mesmo tempo, caso contrário você perderá dados.fonte
sponge
from moreutils também pode ajudar.fold foo.txt | sponge foo.txt
- oufold foo.txt | sponge !$
também deve fazer.O arquivo é aberto para gravação pelo shell antes que o aplicativo possa lê-lo. A abertura do arquivo para gravação o trunca.
fonte
No bash, o operador de redirecionamento de fluxo é
... > foo.txt
esvaziadofoo.txt
antes de avaliar o operando esquerdo .Pode-se usar substituição de comando e imprimir seu resultado como uma solução alternativa. Esta solução ocupa menos caracteres adicionais do que em outras respostas:
Cuidado: este comando não preserva nenhuma nova linha de busca em
foo.txt
. Dê uma olhada na seção de comentários abaixo para obter mais informaçõesAqui, o subshell
$(...)
é avaliado antes do operador de redirecionamento de fluxo>
, daí a preservação de informações.fonte
tmp=$(cmd; printf q); printf '%s' "${tmp%q}"
. Mas você perdeu outro problema com esta resposta: diz "subshell" quando significa "substituição de comando". Sim, as substituições de comando geralmente são sub-conchas, mas não vice-versa, e sub-conchas, em geral, não ajudam a esse problema.