Ich habe ein Programm, das nützliche Informationen erzeugt, stdout
aber auch ausliest stdin
. Ich möchte die Standardausgabe in eine Datei umleiten, ohne die Standardeingabe zu ändern. So weit, so gut: Ich kann:
program > output
und mach nichts in der tty.
Das Problem ist jedoch, dass ich dies im Hintergrund tun möchte. Wenn ich mache:
program > output &
Das Programm wird angehalten ("angehalten (tty input)").
Wenn ich mache:
program < /dev/null > output &
Das Programm wird sofort beendet, da es EOF erreicht.
Es scheint, dass ich in program
etwas hineinpfeifen muss, das auf unbestimmte Zeit nichts tut und nicht liest stdin
. Die folgenden Ansätze funktionieren:
while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &
Dies ist jedoch alles sehr hässlich. Es muss eine elegante Möglichkeit geben, mit Standard-Unix-Dienstprogrammen "nichts auf unbestimmte Zeit zu tun" (um es zu paraphrasieren man true
). Wie könnte ich das erreichen? (Meine Hauptkriterien für Eleganz hier: keine temporären Dateien; kein Warten oder periodisches Aufwecken; keine exotischen Hilfsprogramme; so kurz wie möglich.)
su -c 'program | output &' user
. Ich stelle eine ähnliche Frage zum Erstellen von Hintergrundjobs als akzeptable Methode für die Behandlung eines "Service / Daemons". Ich bemerkte auch, dass ich nicht umleiten konnte,STDERR
ohne auch umzuleitenSTDOUT
. Die Lösung in dem Programa sendetSTDOUT
zuSTDIN
der programB, leitet dannSTDERR
in eine Protokolldatei:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
su -c 'while true; do true; done | cat > ~/output &' user
?1<&-
damit schließen, Ihr Programm beendet wird?Antworten:
In Shells, die sie unterstützen (ksh, zsh, bash4), können Sie
program
als Co-Prozess starten .ksh
:program > output |&
zsh
,bash
:coproc program > output
Das beginnt
program
im Hintergrund, wenn die Eingabe von a umgeleitet wirdpipe
. Das andere Ende des Rohrs ist zur Hülle hin offen.Drei Vorteile dieses Ansatzes
program
stirbt (verwendenwait
, um darauf zu warten)program
wird beendet (wirdeof
auf die Standardeinstellung gesetzt, wenn die Shell beendet wird).quelle
tail -f /dev/null
ist nicht ideal, da es jede Sekunde gelesen wird/dev/null
(aktuelle Versionen von GNU tail unter Linux mit inotify gibt es tatsächlich einen Fehler ).sleep inf
oder sein portableres Äquivalentsleep 2147483647
sind bessere Ansätze für einen Befehl, der dort sitzt und nichts tut, IMO (beachten Sie, dasssleep
einige Shells wieksh93
oder eingebaut sindmksh
).Ich glaube nicht, dass Sie eleganter werden als die
Das haben Sie bereits vorgeschlagen (vorausgesetzt, dies verwendet inotify intern, es sollte kein Polling oder Aufwecken geben, es sollte also ausreichend sein, außer dass es seltsam aussieht).
Sie benötigen ein Dienstprogramm, das auf unbestimmte Zeit ausgeführt wird, dessen Standardausgabe offen bleibt, das jedoch nichts in die Standardausgabe schreibt und das nicht beendet wird, wenn die Standardausgabe geschlossen wird. Sowas
yes
schreibt eigentlich stdout an.cat
wird beendet, wenn die Standardeingabe geschlossen ist (oder was auch immer Sie umleiten). Ich denkesleep 1000000000d
könnte funktionieren, aber dastail
ist eindeutig besser. Meine Debian-Box hat einentailf
Befehl, der sich geringfügig verkürzt.Wie wäre es mit einem anderen Ansatz, wenn Sie das Programm unter laufen lassen
screen
?quelle
tail -f /dev/null
Ansatz am liebsten und finde ihn auch elegant genug, da die Befehlsverwendung dem beabsichtigten Zweck ziemlich genau entspricht.strace tail -f /dev/null
dasstail
Verwendungeninotify
und das Aufwachen in albernen Fällen wie auftretensudo touch /dev/null
. Es ist traurig, dass es anscheinend keine bessere Lösung gibt ... Ich frage mich, welches der richtige Systemanruf wäre, um eine bessere Lösung zu implementieren.pause
, aber es ist nicht direkt einer Shell-Schnittstelle ausgesetzt.screen
, aber dies ist zu Testzwecken, um mehrere Vorkommen des Programms von einem Shell-Skript auszuführen, also ist die Verwendungscreen
ein bisschen übertrieben.sleep infinity
ist die klarste Lösung, die ich kenne.Sie können verwenden,
infinity
weilsleep
eine Gleitkommazahl * akzeptiert wird , die je nach dem dezimal , hexadezimal , unendlich oder naN sein kannman strtod
.* Dies ist nicht Teil des POSIX-Standards, ist also nicht so portabel wie
tail -f /dev/null
. Es wird jedoch in GNU coreutils (Linux) und BSD (verwendet auf Mac) unterstützt (anscheinend nicht unterstützt auf neueren Versionen von Mac - siehe Kommentare).quelle
sleep infinity
auch auf BSD und Mac zu funktionieren .sleep infinity
maximal 24 Tage gewartet wird. wer hat rechtsleep
Dienstprogramm ist nicht auf 24 Tage beschränkt . Es ist nur der erste Systemanruf, der 24 Tage lang inaktiv ist, und danach werden weitere solche Systemanrufe ausgeführt. Siehe meinen Kommentar hier: stackoverflow.com/questions/2935183/…Ja, es
2^31-1
ist eine endliche Zahl, und sie wird nicht für immer laufen , aber ich gebe Ihnen 1000 US-Dollar, wenn der Schlaf endlich aufhört. (Hinweis: bis dahin ist einer von uns tot.)quelle
sleep 2147483647d
...Sie können eine Binärdatei erstellen, die genau das tut mit:
quelle
Hier ist ein weiterer Vorschlag für die Verwendung von Standard-Unix-Dienstprogrammen, um "auf unbestimmte Zeit nichts zu tun" .
Dies löst eine Shell aus, die sofort gesendet wird
SIGSTOP
und den Prozess anhält. Dies wird als "Eingabe" für Ihr Programm verwendet. Das Komplement vonSIGSTOP
istSIGCONT
, dh wenn Sie wissen, dass die Shell die PID 12345 hat, können Siekill -CONT 12345
diese fortsetzen.quelle
Unter Linux können Sie Folgendes tun:
Wenn Sie unter Linux / dev / fd / x öffnen, wobei x ein Dateideskriptor für das schreibende Ende einer Pipe ist, erhalten Sie das lesende Ende der Pipe.
read
Wird also im Grunde nie zurückkehren, weil das einzige, was in diese Pipe geschrieben werden kann, sich selbst ist undread
nichts ausgibt.Es wird auch unter FreeBSD oder Solaris funktionieren, aber aus einem anderen Grund. Wenn Sie dort / dev / fd / 1 öffnen, erhalten Sie die gleiche Ressource wie auf fd 1, die Sie erwartet haben, und wie es die meisten Systeme außer Linux tun, also das Ende der Pipe. Unter FreeBSD und Solaris sind Pipes jedoch bidirektional. Solange
program
also nicht in das Standardverzeichnis geschrieben wird (keine Anwendung),read
kann aus dieser Richtung der Pipe nichts gelesen werden.Auf Systemen, auf denen Pipes nicht bidirektional sind, tritt
read
wahrscheinlich ein Fehler auf, wenn versucht wird, aus einem Nur-Schreib-Dateideskriptor zu lesen. Beachten Sie auch, dass nicht alle Systeme haben/dev/fd/x
.quelle
x
mit bash; weiter mit zsh kannst du es einfach machenread
und es funktioniert (obwohl ich nicht verstehe warum!). Ist dieser Trick Linux-spezifisch oder funktioniert er auf allen * nix-Systemen?read
alleine machst , liest es von stdin. Wenn es sich also um das Terminal handelt, wird Ihre Eingabe gelesen, bis Sie die Eingabetaste drücken.read
und es funktioniert ?read | program > output
, was Sie vorgeschlagen haben. (Und ich verstehe nicht warum.)Die
read
Lösung von Stéphane Chazelas funktioniert auch unter Mac OS X, wenn eine Lese-FD geöffnet wird/dev/fd/1
.Um
tail -f /dev/null
in einem Skript töten zu können (z. B. mit SIGINT), müssen Sie dentail
Befehl und im Hintergrund ausführenwait
.quelle
Weiterleitung
/dev/zero
als Standardeingabe!quelle