Quero evitar arquivos temporários se meu programa travar.
O UNIX é maravilhoso porque você pode manter um arquivo aberto - mesmo depois de excluí-lo.
Portanto, se você abrir o arquivo, exclua-o imediatamente eentãoSe você fizer o processamento lento, há grandes chances de que, mesmo que o programa trave, o usuário não precise limpar o arquivo.
No shell, muitas vezes vejo algo semelhante a:
generate-the-file -o the-file
[...loads of other stuff that may use stdout or not...]
do_slow_processing < the-file
rm the-file
Mas se o programa travar antes rm
o usuário terá que limpar o arquivo the-file
.
Em Perl você pode fazer:
open(my $filehandle, "<", "the-file") || die;
unlink("the-file");
while(<$filehandle>) {
# Do slow processing stuff here
print;
}
close $filehandle;
Em seguida, o arquivo é removido assim que é aberto.
Existe uma construção semelhante no shell?
Responder1
Isso é testado em csh, tcsh, sh, ksh, zsh, bash, ash, sash:
echo foo > the-file
(rm the-file; cat) < the-file | do_slow_processing
do_other_stuff
ou se preferir:
(rm the-file; do_slow_processing) < the-file
do_other_stuff
Curiosamente, também funciona para fifos:
mkfifo the-fifo
(rm the-fifo; cat) < the-fifo | do_slow_processing &
echo foo > the-fifo
Isso ocorre porque o leitor fica bloqueado até que algo seja escrito.
Responder2
generate-the-file > the-file
exec 5< the-file
rm the-file
...
do_slow_processing 0<&5
Notas:
- Você precisa executar exec sem executável, então isso afeta os descritores do próprio shell
- Somente até fd 9 disponível
- Você pode usar /proc/self/fd/X se precisar de um nome de arquivo. Essa interface não é portátil entre versões UNIX (embora provavelmente funcione para você).
- Tentar ler novamente o fd (por exemplo, duas chamadas para
cat 0<&5
) falhará porque você está no EOF. Você precisaria retroceder ou superá-lo lendo via/proc/self/fd/X
- Na maioria dos casos, como acima, você poderia ficar sem um arquivo real e fazer um simples
generate-the-file | do_slow_processing
Atualizar:
O OP menciona que generate-the-file
pode não produzir sua saída em stdout. Existem algumas expressões idiomáticas para isso:
- Especifique um arquivo de saída de
-
. É comum aceitar um nome de arquivo de saída - para significar stdout. Isso éreconhecido por POSIX.1-2017:Diretriz 13: Para utilitários que usam operandos para representar arquivos a serem abertos para leitura ou gravação, o operando '-' deve ser usado para significar apenas entrada padrão (ou saída padrão quando estiver claro no contexto que um arquivo de saída está sendo especificado) ou um arquivo chamado -.
(para utilitários diferentes daqueles onde eles definem isso explicitamente, é definido pela implementação, mas há uma boa chance de que seja suportado pela sua generate-the-file
ferramenta)
Utilize
/dev/stdout
ou/proc/self/fd/1
. Dependente do sistema operacional, consulteQuão portáteis são /dev/stdin, /dev/stdout e /dev/stderr?Use substituição de processo. bash permitirá que você escreva
>(process substitution)
como um nome de arquivo. Por exemplo:wget -O >(rot13 > question.txt)https://unix.stackexchange.com/q/579535/70346
Isso não funcionará em todos os shells e requer suporte do sistema operacional para nomes de arquivos fd.
Responder3
No bash
shell, a maneira de lidar com a limpeza é usando o EXIT trap
embutido (de dentro de um bash
shell, digite help trap
):
trap 'rm temp-file' EXIT
Esse recurso também existe no dash
shell, frequentemente apelidado de sh
distribuições Linux modernas.