Ich habe Probleme beim Debuggen eines Segfault-Programms, da ich die Ausgabe direkt vor dem Segfault benötige. Diese geht jedoch verloren, wenn ich die Ausgabe an eine Datei weitergebe. Laut dieser Antwort: /unix//a/17339/22615 . Dies liegt daran, dass der Ausgabepuffer des Programms beim Anschließen an ein Terminal sofort gelöscht wird, beim Anschließen an eine Pipe jedoch nur an bestimmten Punkten. Ein paar Fragen hier:
Wie bestimmt ein Programm, mit welcher Standardausgabe es verbunden ist?
Wie bewirkt der Befehl "script" dasselbe Verhalten wie beim Schreiben auf ein Terminal?
Kann dies ohne den Skriptbefehl erreicht werden?
Antworten:
Angeben, ob ein Dateideskriptor auf ein Endgerät verweist
Ein Programm kann mithilfe der
isatty()
Standard-C-Funktion feststellen, ob einem tty-Gerät ein Dateideskriptor zugeordnet ist (darunter befindet sich im Allgemeinen ein harmloser tty-spezifischerioctl()
Systemaufruf, der mit einem Fehler zurückgegeben würde, wenn der fd nicht auf ein tty-Gerät verweist). .Das Dienstprogramm
[
/test
kann dies mit seinem-t
Operator tun .Libc-Funktionsaufrufe auf einem GNU / Linux-System verfolgen:
Systemaufrufe verfolgen:
Sagen, ob es auf eine Pfeife zeigt
Um festzustellen, ob ein fd mit einer Pipe / einem fifo verknüpft ist, können Sie den
fstat()
Systemaufruf verwenden , der eine Struktur zurückgibt, derenst_mode
Feld den Typ und die Berechtigungen der auf diesem fd geöffneten Datei enthält. DasS_ISFIFO()
Standard-C-Makro kann in diesemst_mode
Feld verwendet werden, um zu bestimmen, ob es sich bei dem FD um eine Pipe / FIFO handelt.Es gibt kein Standarddienstprogramm, das a ausführen kann
fstat()
, aber es gibt mehrere inkompatible Implementierungen einesstat
Befehls, die dies ausführen können.zsh
'sstat
builtin, mitstat -sf "$fd" +mode
dem der Modus als Zeichenfolgendarstellung zurückgegeben wird, deren erstes Zeichen den Typ darstellt (p
für Pipe). GNUstat
kann dasselbe tunstat -c %A - <&"$fd"
, muss aber auchstat -c %F - <&"$fd"
den Typ alleine melden . Mit BSDstat
:stat -f %St <&"$fd"
oderstat -f %HT <&"$fd"
.Sagen, ob es suchbar ist
Anwendungen interessieren sich im Allgemeinen nicht dafür, ob stdout eine Pipe ist. Sie können sich darum kümmern, dass es suchbar ist (obwohl sie im Allgemeinen nicht entscheiden, ob sie puffern wollen oder nicht).
Um zu testen, ob ein fd suchbar ist (Pipes, Sockets, tty-Geräte sind nicht suchbar, reguläre Dateien und die meisten Blockgeräte im Allgemeinen), kann ein relativer
lseek()
Systemaufruf mit einem Offset von 0 (also harmlos) versucht werden .dd
ist ein Standarddienstprogramm, zu dem eine Schnittstelle gehört, daslseek()
jedoch für diesen Test nicht verwendet werden kann, da Implementierungen überhaupt nicht aufgerufen würden,lseek()
wenn Sie nach einem Offset von 0 fragen.Die
zsh
undksh93
Shells haben jedoch nach Operatoren gesucht:Pufferung deaktivieren
Der
script
Befehl verwendet ein Pseudo-Terminal-Paar, um die Ausgabe eines Programms zu erfassen, sodass das stdout (und stdin und stderr) des Programms ein Pseudo-Terminal-Gerät ist.Wenn sich die Standardausgabe auf ein Endgerät bezieht, ist im Allgemeinen noch eine gewisse Pufferung vorhanden, die jedoch zeilenbasiert ist.
printf
/puts
und co schreiben erst etwas, wenn ein Zeilenumbruch ausgegeben werden soll. Bei anderen Dateitypen erfolgt die Pufferung in Blöcken (von wenigen Kilobytes).Es gibt mehrere Optionen , um die Pufferung zu deaktivieren , die in einer Reihe von Fragen und Antworten hier diskutiert werden (Suche nach unbuffer oder STDBUF , kann nicht Redirect Schnitt Ausgabe einige Ansätze gibt) entweder durch einen Pseudo-Terminal wie die Verwendung kann erfolgen durch
socat
/script
/expect
/unbuffer
(einexpect
Skript) /zsh
'szpty
oder durch Einfügen von Code in die ausführbare Datei, um die Pufferung durch GNUs oder FreeBSDs zu deaktivierenstdbuf
.quelle
/proc
Verzeichnis zu durchsuchen und für jedes/proc/<integer>/
Verzeichnis nach einem/proc/<integer>/fd/
Dateideskriptor mit derselben Inode-Nummer inpipefs
serverfault.com/q/48330/363611 zu suchen. Dies ist jedoch nur in Skripten nützlich, wenn die beschriebenen Syscalls nicht verwendet werden können in Stephanes Antwort, und ist eher eine Problemumgehung als die richtige Lösung IMHOlseek
wird dies auf Terminals und anderen Zeichengeräten erfolgreich sein und einfach einen Zähler zurücksetzen / setzen, der bei jedem erfolgreichen Lesen () erhöht wird. Ich weiß nicht, ob dies sie "suchbar" macht.