Ich möchte vermeiden, dass temporäre Dateien herumliegen, wenn mein Programm abstürzt.
Das Wunderbare an UNIX ist, dass Sie eine Datei geöffnet lassen können – sogar nachdem Sie sie gelöscht haben.
Wenn Sie die Datei öffnen, löschen Sie sie sofort undDannWenn Sie die langsame Verarbeitung durchführen, ist die Wahrscheinlichkeit hoch, dass der Benutzer die Datei nicht bereinigen muss, selbst wenn Ihr Programm abstürzt.
In der Shell sehe ich oft etwas Ähnliches wie:
generate-the-file -o the-file
[...loads of other stuff that may use stdout or not...]
do_slow_processing < the-file
rm the-file
Wenn das Programm jedoch vorher abstürzt, rm
muss der Benutzer die Bereinigung durchführen the-file
.
In Perl können Sie Folgendes tun:
open(my $filehandle, "<", "the-file") || die;
unlink("the-file");
while(<$filehandle>) {
# Do slow processing stuff here
print;
}
close $filehandle;
Anschließend wird die Datei sofort nach dem Öffnen entfernt.
Gibt es eine ähnliche Konstruktion in Shell?
Antwort1
Dies wird in csh, tcsh, sh, ksh, zsh, bash, ash, sash getestet:
echo foo > the-file
(rm the-file; cat) < the-file | do_slow_processing
do_other_stuff
oder wenn Sie es vorziehen:
(rm the-file; do_slow_processing) < the-file
do_other_stuff
Interessanterweise funktioniert es auch für FIFOs:
mkfifo the-fifo
(rm the-fifo; cat) < the-fifo | do_slow_processing &
echo foo > the-fifo
Dies liegt daran, dass der Reader blockiert ist, bis etwas geschrieben wird.
Antwort2
generate-the-file > the-file
exec 5< the-file
rm the-file
...
do_slow_processing 0<&5
Anmerkungen:
- Sie müssen exec ohne ausführbare Datei ausführen, sodass die Deskriptoren der Shell selbst betroffen sind
- Nur bis FD 9 lieferbar
- Sie können /proc/self/fd/X verwenden, wenn Sie einen Dateinamen benötigen. Diese Schnittstelle ist nicht zwischen UNIX-Varianten portierbar (bei Ihnen funktioniert sie aber wahrscheinlich).
- Der Versuch, das fd erneut zu lesen (z. B. zwei Aufrufe von
cat 0<&5
), schlägt fehl, da Sie sich am EOF befinden. Sie müssen es zurückspulen oder es durch Lesen über überwinden/proc/self/fd/X
- In den meisten Fällen wie oben können Sie jedoch auf eine tatsächliche Datei verzichten und eine einfache
generate-the-file | do_slow_processing
Aktualisieren:
Der OP erwähnt, dass generate-the-file
die Ausgabe möglicherweise nicht in stdout erfolgt. Dafür gibt es einige Redewendungen:
- Geben Sie eine Ausgabedatei von an
-
. Es ist üblich, einen Ausgabedateinamen von - zu akzeptieren, um stdout zu bedeuten. Dies istbestätigt durch POSIX.1-2017:Leitlinie 13: Bei Dienstprogrammen, die Operanden verwenden, um Dateien darzustellen, die zum Lesen oder Schreiben geöffnet werden sollen, sollte der Operand „-“ nur für die Standardeingabe (oder Standardausgabe, wenn aus dem Kontext klar hervorgeht, dass eine Ausgabedatei angegeben wird) oder für eine Datei mit dem Namen „-“ verwendet werden.
(Bei anderen Dienstprogrammen als denen, bei denen dies explizit definiert ist, ist es implementierungsdefiniert, aber es besteht eine gute Chance, dass es von Ihrem generate-the-file
Tool unterstützt wird)
Verwenden Sie
/dev/stdout
oder/proc/self/fd/1
. Betriebssystemabhängig, sieheWie portabel sind /dev/stdin, /dev/stdout und /dev/stderr?Verwenden Sie Prozesssubstitution. Bash ermöglicht Ihnen das Schreiben
>(process substitution)
als Dateiname. Beispiel:wget -O >(rot13 > frage.txt)https://unix.stackexchange.com/q/579535/70346
Dies funktioniert nicht auf allen Shells und erfordert Betriebssystemunterstützung für FD-Dateinamen.
Antwort3
In der bash
Shell können Sie die Bereinigung mithilfe des trap
integrierten EXIT-Befehls durchführen (geben Sie innerhalb einer bash
Shell ein help trap
):
trap 'rm temp-file' EXIT
Diese Funktion ist auch in der dash
Shell vorhanden und wird sh
in modernen Linux-Distributionen häufig als Alias verwendet.