Hallo,
ich habe hier eine kleine Kopfnuss mein Ziel ist, den Output eines Befehls in eine Datei zu schreiben, aber nur wenn er nicht leer ist
Lösungen mit temporären Dateien und Variablen habe ich bereits gefunden allerdings bin ich mir sicher, dass es noch einfachere Ansätze mit Pipen und logischen Operatoren gibt
Vielen Dank René
On Wed, Jul 11, 2018 at 09:01:18AM +0200, Rene Terlecki wrote:
ich habe hier eine kleine Kopfnuss mein Ziel ist, den Output eines Befehls in eine Datei zu schreiben, aber nur wenn er nicht leer ist
Lösungen mit temporären Dateien und Variablen habe ich bereits gefunden allerdings bin ich mir sicher, dass es noch einfachere Ansätze mit Pipen und logischen Operatoren gibt
Ich glaube nicht, dass das rein in der Shell funktionieren kann. Das Problem ist, dass die Shell die Datei aufmacht, in die umgeleitet wird und dann den offenen Dateidescriptor an das Programm übergibt, dass den Output erzeugt. Das Programm schreibt dann einfach da rein. Beim Öffnen der Datei wird diese aber schon angelegt.
Die Lösung ist relativ einfach mit einem externen Programm zu erledigen, das quasi wie "cat" funktioniert, also Daten einfach durchleitet, aber die Ausgabedatei selbst aufmacht und zwar erst dann, wenn zum ersten Mal Daten ankommen. Ich weiß von keinem Programm, dass das macht, aber es ist auch nicht schwierig, sowas zu schreiben.
Jochen
On Thu, Jul 12, 2018 at 09:09:49AM +0200, Jochen Topf jochen@remote.org wrote:
On Wed, Jul 11, 2018 at 09:01:18AM +0200, Rene Terlecki wrote:
ich habe hier eine kleine Kopfnuss mein Ziel ist, den Output eines Befehls in eine Datei zu schreiben, aber nur wenn er nicht leer ist
Lösungen mit temporären Dateien und Variablen habe ich bereits gefunden allerdings bin ich mir sicher, dass es noch einfachere Ansätze mit Pipen und logischen Operatoren gibt
Ich glaube nicht, dass das rein in der Shell funktionieren kann. Das Problem ist, dass die Shell die Datei aufmacht, in die umgeleitet wird und dann den offenen Dateidescriptor an das Programm übergibt, dass den Output erzeugt. Das Programm schreibt dann einfach da rein. Beim Öffnen der Datei wird diese aber schon angelegt.
Die Lösung ist relativ einfach mit einem externen Programm zu erledigen, das quasi wie "cat" funktioniert, also Daten einfach durchleitet, aber die Ausgabedatei selbst aufmacht und zwar erst dann, wenn zum ersten Mal Daten ankommen. Ich weiß von keinem Programm, dass das macht, aber es ist auch nicht schwierig, sowas zu schreiben.
Hier hast du eins:
~> cat t.pl #!/usr/bin/perl # #
use strict; use warnings;
my $file = $ARGV[0]; my $HANDLE = undef;
while(<STDIN>) { unless(defined($HANDLE)) { if($file) { open($HANDLE,">>",$file) or $HANDLE = *STDOUT; } else { $HANDLE = *STDOUT; } } print $HANDLE $_; } ~> echo -n "" | perl t.pl /tmp/foo ~> cat /tmp/foo cat: /tmp/foo: No such file or directory ~> echo "foo" | perl t.pl /tmp/foo ~> cat /tmp/foo foo ~>
Ciao, Thomas
Jochen Topf jochen@remote.org (Do 12 Jul 2018 09:09:49 CEST):
Die Lösung ist relativ einfach mit einem externen Programm zu erledigen, das quasi wie "cat" funktioniert, also Daten einfach durchleitet, aber die Ausgabedatei selbst aufmacht und zwar erst dann, wenn zum ersten Mal Daten ankommen. Ich weiß von keinem Programm, dass das macht, aber es ist auch nicht schwierig, sowas zu schreiben.
#!/bin/bash read || exit test $# = 1 && exec 1>"$1" printf '%s\n' "$REPLY" exec cat
-- Heiko
Am 12.07.2018 um 14:50 schrieb Heiko Schlittermann:
Jochen Topf jochen@remote.org (Do 12 Jul 2018 09:09:49 CEST):
Die Lösung ist relativ einfach mit einem externen Programm zu erledigen, das quasi wie "cat" funktioniert, also Daten einfach durchleitet, aber die Ausgabedatei selbst aufmacht und zwar erst dann, wenn zum ersten Mal Daten ankommen. Ich weiß von keinem Programm, dass das macht, aber es ist auch nicht schwierig, sowas zu schreiben.
#!/bin/bash read || exit test $# = 1 && exec 1>"$1" printf '%s\n' "$REPLY" exec cat
-- Heiko
Danke für die Ansätze
mein aktueller Stand ist v=$(......); [[ -n $v ]] && echo "$v" > file das ist übersichtlich und macht das, was es soll nur die Variable gefällt mir nicht, da man immer aufpassen muss, dass dadurch im Skript nicht irgendwas unerwartetes passiert
allerdings habe ich auch schon folgenden Ansatz versucht ..... | xargs --no-run-if-empty --null > file
ich wollte gern auf zusätzliche Abhängigkeiten wie Shellfunktionen oder andere Skripte verzichten
ciao Rene
Rene Terlecki rene.terlecki@gmx.de (Do 12 Jul 2018 16:29:22 CEST):
v=$(......); [[ -n $v ]] && echo "$v" > file das ist übersichtlich und macht das, was es soll nur die Variable gefällt mir nicht, da man immer aufpassen muss, dass dadurch im Skript nicht irgendwas unerwartetes passiert
Was meinst Du genau? Das einzige, was Dir passieren kann, ist daß $v z.B. ein "-n" enthält, also eine Option, die echo versteht. Du könntest das lösen mit
printf '%s\n' "$v" oder cat <<<$v > file
allerdings habe ich auch schon folgenden Ansatz versucht ..... | xargs --no-run-if-empty --null > file
Da wird file wieder angelegt, bevor irgendwas los geht. Ansonsten ist das mit dem xargs schon interessant :)
-- Heiko
Am 12.07.2018 um 16:34 schrieb Heiko Schlittermann:
Rene Terlecki rene.terlecki@gmx.de (Do 12 Jul 2018 16:29:22 CEST):
v=$(......); [[ -n $v ]] && echo "$v" > file das ist übersichtlich und macht das, was es soll nur die Variable gefällt mir nicht, da man immer aufpassen muss, dass dadurch im Skript nicht irgendwas unerwartetes passiert
Was meinst Du genau? Das einzige, was Dir passieren kann, ist daß $v z.B. ein "-n" enthält, also eine Option, die echo versteht. Du könntest das lösen mit
printf '%s\n' "$v"
oder cat <<<$v > file
allerdings habe ich auch schon folgenden Ansatz versucht ..... | xargs --no-run-if-empty --null > file
Da wird file wieder angelegt, bevor irgendwas los geht. Ansonsten ist das mit dem xargs schon interessant :)
-- Heiko
die Datei existiert die ganze Zeit sie soll nur überschrieben werden (wenn es was zum Überschreiben gibt) was nicht passieren darf, ist, dass die Datei geleert wird, indem "nichts" reingeschrieben wird
das Problem ist, dass ich den Output sowohl auf "nicht leer" testen muss und ihn nur dann in die Datei schreiben will, wenn er nicht leer ist
ciao, Rene
On Thu, Jul 12, 2018 at 06:24:18PM +0200, Rene wrote:
die Datei existiert die ganze Zeit sie soll nur überschrieben werden (wenn es was zum Überschreiben gibt) was nicht passieren darf, ist, dass die Datei geleert wird, indem "nichts" reingeschrieben wird
das Problem ist, dass ich den Output sowohl auf "nicht leer" testen muss und ihn nur dann in die Datei schreiben will, wenn er nicht leer ist
Schreib den output in eine andere Datei und wenn die Datei nicht leer ist, mach ein "mv" der tmp-Datei auf die alte Datei. Das hat auch den Vorteil, dass ein anderer Prozess, der diese Datei liest, immer eine gültige Datei bekommt und nicht eine vielleicht gerade halb geschriebene.
Jochen
Jochen Topf jochen@remote.org (Do 12 Jul 2018 18:36:08 CEST):
Schreib den output in eine andere Datei und wenn die Datei nicht leer ist, mach ein "mv" der tmp-Datei auf die alte Datei. Das hat auch den
mv ist doof, wenn die Zieldatei ein Symlink ist oder mehr als eine Referenz (Hardlink) hat.
-- Heiko
Du hast zwar bereits deine Anforderung um 180° umgedreht und aus "Die Datei soll nicht geschrieben werden, wenn es keinen Input gibt" zu "Die bestehende Datei soll nicht überschrieben werden, wenn es keinen Input gibt", aber der folgende Ansatz liefert doch eine interessante Lösung für beide Problemstellungen.
Am 12.07.2018 um 16:29 schrieb Rene Terlecki:
allerdings habe ich auch schon folgenden Ansatz versucht ..... | xargs --no-run-if-empty --null > file
Heiko hat ja schon darauf hingewiesen, dass Die Datei trotzdem zum Schreiben geöffnet und daher geleert wird, bevor überhaupt irgendein Prozess der Pipe läuft.
echo "non empty file" > non-empty-file.txt echo "" | xargs --no-run-if-empty > non-empty-file.txt
Aber damit fehlt dir doch nur noch ein Baustein: Was könnte xargs *nicht* starten, wenn der Eingang der Pipe keinen Input liefert.
Und da wären wir bei einer schicken Lösung für beide Probleme, denn die Datei wird weder überschrieben noch angelegt:
echo "non empty file" > non-empty-file.txt echo "" | xargs --no-run-if-empty tee non-empty-file.txt
Am 12.07.2018 um 23:38 schrieb Uwe Koloska:
Du hast zwar bereits deine Anforderung um 180° umgedreht und aus "Die Datei soll nicht geschrieben werden, wenn es keinen Input gibt" zu "Die bestehende Datei soll nicht überschrieben werden, wenn es keinen Input gibt", aber der folgende Ansatz liefert doch eine interessante Lösung für beide Problemstellungen.
Am 12.07.2018 um 16:29 schrieb Rene Terlecki:
allerdings habe ich auch schon folgenden Ansatz versucht ..... | xargs --no-run-if-empty --null > file
Heiko hat ja schon darauf hingewiesen, dass Die Datei trotzdem zum Schreiben geöffnet und daher geleert wird, bevor überhaupt irgendein Prozess der Pipe läuft.
echo "non empty file" > non-empty-file.txt echo "" | xargs --no-run-if-empty > non-empty-file.txt
Aber damit fehlt dir doch nur noch ein Baustein: Was könnte xargs *nicht* starten, wenn der Eingang der Pipe keinen Input liefert.
Und da wären wir bei einer schicken Lösung für beide Probleme, denn die Datei wird weder überschrieben noch angelegt:
echo "non empty file" > non-empty-file.txt echo "" | xargs --no-run-if-empty tee non-empty-file.txt
Hallo,
der Ansatz mit tee war vielversprechend, doch leider funktioniert er bei mir nicht denke, dass tee keinen Input mehr hat, der angezeigt und in eine Datei geschrieben werden kann
Danke Rene
On 13.07.2018 08:23, Rene Terlecki wrote:
der Ansatz mit tee war vielversprechend, doch leider funktioniert er bei mir nicht
Autsch, bei mir auch nicht:
rm non-empty-file.txt echo -e "1. Zeile\n2. Zeile" | xargs --no-run-if-empty tee non-empty-file.txt
Die Datei wird zwar angelegt, ist aber leer. Typischer Fall von den Test für den Fall von dem ich weiß, dass er funktioniert, kann ich weglassen.
denke, dass tee keinen Input mehr hat, der angezeigt und in eine Datei geschrieben werden kann
Ja, es ist so wie Heiko in der anderen Antwort schrieb: xargs nimmt die in der Pipe ankommenden Daten als Argumente für das Kommando und damit ist der Input leer.
Und es gibt kein Kommando, das seine Argumente in eine Datei schreibt, weil es dafür ja die Ausgabeumleitung gibt ...
Also leider keine Lösung :-(
Uwe Koloska ml@koloro.de (Do 12 Jul 2018 23:38:09 CEST):
Aber damit fehlt dir doch nur noch ein Baustein: Was könnte xargs *nicht* starten, wenn der Eingang der Pipe keinen Input liefert.
Und da wären wir bei einer schicken Lösung für beide Probleme, denn die Datei wird weder überschrieben noch angelegt:
echo "non empty file" > non-empty-file.txt echo "" | xargs --no-run-if-empty tee non-empty-file.txt
Ja, das dachte ich auch, ABER, wenn jetzt aus der Pipe Daten kommen, dann entstehen Kommandozeilen der Art
tee non-empty-file.txt ZEILE1 ZEILE2 ZEILE3 tee non-empty-file.txt ZEILE4 ZEILE5 ZEILE6
Das macht nicht, was er braucht, er möchte die Zeilen ja dann in sein File haben.
-- Heiko
Heiko Schlittermann hs@schlittermann.de (Do 12 Jul 2018 14:50:20 CEST):
Jochen Topf jochen@remote.org (Do 12 Jul 2018 09:09:49 CEST):
Die Lösung ist relativ einfach mit einem externen Programm zu erledigen, das quasi wie "cat" funktioniert, also Daten einfach durchleitet, aber die Ausgabedatei selbst aufmacht und zwar erst dann, wenn zum ersten Mal Daten ankommen. Ich weiß von keinem Programm, dass das macht, aber es ist auch nicht schwierig, sowas zu schreiben.
#!/bin/bash read || exit test $# = 1 && exec 1>"$1" printf '%s\n' "$REPLY" exec cat
Hier noch einer mit Perl:
perl -e 'sysread(STDIN, $_, 1) or exit 0; open(STDOUT, ">", shift); print; exec "cat"'
Oder als Script etwas leserlicher:
#!/usr/bin/perl sysread(STDIN, $_, 1) or exit 0; open(STDOUT, '>', shift // die "$0: Need a file name"); print; exec 'cat';
Oder Pure Perl, aber das hatte Thomas schon, mit Fehlerbehandlung left as an excercise to the reader ;)
#!/usr/bin/perl die "Usage: $0 FILE\n" unless @ARGV == 1; $/ = \4096; # use 4k chunks, not line by line defined($_ = <STDIN>) and open(STDOUT, '>', shift) and print and print while <STDIN>;
-- Heiko
Heiko Schlittermann hs@schlittermann.de (Sa 14 Jul 2018 12:57:00 CEST): …
#!/usr/bin/perl die "Usage: $0 FILE\n" unless @ARGV == 1; $/ = \4096; # use 4k chunks, not line by line defined($_ = <STDIN>) and open(STDOUT, '>', shift) and print and print while <STDIN>;
Habe eben versucht, etwas noch cooleres mit select(2) zu machen, aber da select() auch zurückkehrt, wenn der Eingabestrom geschlossen wird (ohne Daten geliefert zu haben), müsste man doch wenigstens ein getc(), ungetch() machen vor dem exec(), und dann wird es nicht eleganter als das, was wir schon haben.
Und getchar(), ungetchar() arbeiten mit FILE*, da haben wir schon was im Buffer, bevor wir exec() aufrufen können, das fehlt dann am Ende.
-- Heiko
Rene Terlecki rene.terlecki@gmx.de (Mi 11 Jul 2018 09:01:18 CEST):
ich habe hier eine kleine Kopfnuss mein Ziel ist, den Output eines Befehls in eine Datei zu schreiben, aber nur wenn er nicht leer ist
Genau das passiert doch. Wenn es keinen Output gibt, wird auch keiner geschrieben.
Du meinst vermutlich, daß das File nicht angelegt werden soll… das hat Dir Rene schon ganz gut beantwortet. Die Shell legt das File an, bevor sie feststellt, ob das Programm überhaupt laufen wird.
Kannst also nur sowas oder ähnliches machen (was vermutlich auf sowas wie das hier skizzierte hinausläuft):
foo > file; test -s file || rm file
-- Heiko
Heiko Schlittermann hs@schlittermann.de (Do 12 Jul 2018 11:25:23 CEST):
Rene Terlecki rene.terlecki@gmx.de (Mi 11 Jul 2018 09:01:18 CEST):
ich habe hier eine kleine Kopfnuss mein Ziel ist, den Output eines Befehls in eine Datei zu schreiben, aber nur wenn er nicht leer ist
Genau das passiert doch. Wenn es keinen Output gibt, wird auch keiner geschrieben.
Du meinst vermutlich, daß das File nicht angelegt werden soll… das hat Dir Rene schon ganz gut beantwortet. Die Shell legt das File an, bevor
Jochen, Rene bist Du ja selbst.
-- heiko
lug-dd@mailman.schlittermann.de