Warum kann ich nicht "tail -f / proc / $ pid / fd / 1"?

10

Ich habe ein einfaches Skript geschrieben, echodessen PID:

#/bin/bash

while true; do
    echo $$;
    sleep 0.5;
done

Ich führe das Skript (es steht 3844immer wieder) in einem Terminal aus und versuche, tailden Dateideskriptor in einem anderen zu verwenden:

$ tail -f /proc/3844/fd/1

Es druckt nichts auf den Bildschirm und hängt bis ^c. Warum?

Außerdem sind alle STD-Dateideskriptoren (IN / OUT / ERR) mit denselben Punkten verknüpft:

$ ls -l /proc/3844/fd/
total 0
lrwx------ 1 mg mg 64 sie 29 13:42 0 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 1 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 2 -> /dev/pts/14
lr-x------ 1 mg mg 64 sie 29 13:42 254 -> /home/user/test.sh
lrwx------ 1 mg mg 64 sie 29 13:42 255 -> /dev/pts/14

Ist das normal?

Ausführen von Ubuntu GNOME 14.04.

Wenn Sie der Meinung sind, dass diese Frage zu SO oder SU anstelle von UL gehört, sagen Sie es.

cprn
quelle

Antworten:

13

Machen Sie ein straceaus tail -f, es erklärt alles. Der interessante Teil:

13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 fstatfs(3, {...}) = 0
13791 inotify_init()                    = 4
13791 inotify_add_watch(4, "/path/to/file", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1
13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 read(4, 0xd981c0, 26)             = -1 EINTR (Interrupted system call)

Was es macht? Es richtet einen inotifyHandler für die Datei ein und wartet dann, bis mit dieser Datei etwas passiert. Wenn der Kernel tailüber diesen inotify-Handler sagt , dass die Datei geändert wurde (normalerweise wurde sie angehängt), dann tail1) sucht 2) liest die Änderungen 3) schreibt sie auf den Bildschirm.

/proc/3844/fd/1Auf Ihrem System befindet sich eine symbolische Verknüpfung zu /dev/pts/14einem Zeichengerät. Es gibt keine "Speicherkarte", auf die dadurch zugegriffen werden könnte. Somit gibt es nichts, dessen Änderungen an der inotify signiert werden könnten, da es keine Festplatte oder keinen Speicherbereich gibt, auf die damit zugegriffen werden könnte.

Dieses Zeichengerät ist ein virtuelles Terminal, das praktisch so funktioniert, als wäre es ein Netzwerk-Socket. Programme, die auf diesem virtuellen Terminal ausgeführt werden, stellen eine Verbindung zu diesem Gerät her (so als ob Sie über einen TCP-Port telnetiert hätten) und schreiben, in was sie schreiben möchten. Es gibt auch komplexere Dinge, zum Beispiel das Sperren des Bildschirms, Terminalsteuerungssequenzen und dergleichen, die normalerweise von ioctl()Anrufen erledigt werden .

Ich denke, Sie möchten sich irgendwie ein virtuelles Terminal ansehen. Es kann unter Linux durchgeführt werden, ist aber nicht so einfach, es benötigt einige Netzwerk-Proxy-ähnliche Funktionen und ein wenig knifflige Verwendung dieser ioctl()Aufrufe. Aber es gibt Werkzeuge, die das können.

Derzeit kann ich mich nicht erinnern, welches Debian-Paket das Tool für dieses Ziel hat, aber mit ein wenig googeln könnte man das wahrscheinlich leicht finden.

Erweiterung: Wie hier bei @Jajesh erwähnt (gib ihm eine +1, wenn du mir gegeben hast), heißt das Tool watch.

Erweiterung # 2: @kelnos erwähnt, eine einfache cat /dev/pts/14waren auch genug. Ich habe das versucht und ja, es hat funktioniert, aber nicht richtig. Ich habe nicht viel damit experimentiert, aber es scheint mir, als ob eine Ausgabe, die in dieses virtuelle Terminal geht, entweder an den catBefehl oder an seinen ursprünglichen Ort geht und niemals an beide. Aber es ist nicht sicher.

Peter - Setzen Sie Monica wieder ein
quelle
peterhs antwort über tailist richtig (das inotify watch bit), aber er ist insofern falsch, als es eigentlich sehr einfach ist, das zu tun, was man will: einfach verwenden catstatt tail.
Kelnos
@kelos Danke, ich werde das versuchen und meine Antwort mit den Ergebnissen erweitern.
Peterh
@kelnos catfunktioniert auch bei mir nicht, es hängt genauso wie der Schwanz und alles was ich tun kann ist ctrl+c.
cprn
1
Ich verstehe es immer noch nicht. Ich habe zu geändert echo $$, echo $$ >> foojetzt gibt es eine Datei und der Prozess öffnet sie und hängt sie alle 0,5 Sekunden an. Ich kann immer noch nicht über den Dateideskriptor darauf zugreifen und alle Dateideskriptoren in /proc/$pid/fd/(aber 254, die auf das test.shSkript selbst verweisen) verlinken auf /dev/pts/14. Wie schreibt Bash-Zugriff foodarauf?
cprn
1
seltsamerweise scheint es nur in einigen Situationen zu funktionieren. Mit dem Skript in der Frage funktioniert es nicht. aber wenn ich "echo $$" in einer Shell mache und dann FD 1 auf dieser PID in einer anderen Shell, wird alles, was ich in die erste Shell tippe, in der zweiten wiedergegeben.
Kelnos
4

Dateien in /dev/ptssind keine regulären Dateien, sondern Handles für virtuelle Terminals. Ein ptsVerhalten zum Lesen und Schreiben ist nicht symmetrisch (das heißt, was dort geschrieben ist, kann später daraus gelesen werden, wie eine reguläre Datei oder ein FIFO / eine Pipe), sondern wird durch den Prozess vermittelt, der das virtuelle Terminal erstellt hat: Einige gängige sind xterm oder ssh oder agetty oder screen. Der Steuerungsprozess sendet normalerweise Tastendrücke an Prozesse, die die ptsDatei lesen , und rendert auf dem Bildschirm, was sie auf die Datei schreiben pts.

So tail -f /dev/pts/14werden die Tasten gedruckt, die Sie auf das Terminal tippen, von dem aus Sie Ihr Skript gestartet haben, und wenn Sie dies tun, wird echo meh > /dev/pts/14die mehNachricht im Terminal angezeigt.

pqnet
quelle
Sie haben Recht zu sagen, dass ich auf das pts-Gerät schreiben kann, aber ich kann anscheinend nicht daraus lesen. Wie in: tail -f /dev/pts/14Druckt nicht die Tasten, die ich auf diesem Terminal tippe. Es ist jedoch eine interessante Antwort. Vielen Dank.
cprn
0

Vor einiger Zeit habe ich eine Art Problemumgehung gefunden , die manchmal die Notwendigkeit beantwortet, zu überprüfen, was an STDOUT ausgegeben wird, vorausgesetzt, Sie haben einen pidTeil des Prozesses und können die Augen unfreundlicher Ergebnisse entblößen:

sudo strace -p $pid 2>&1 | grep write\(
cprn
quelle
-1

Ich denke, dafür müssen Sie die Ausgabe beobachten, anstatt sie zu verfolgen.

$ watch -n2 ls -l /proc/3844/fd/

Hoffe das ist was du brauchst.

Jayesh
quelle
2
Dieser Befehl zeigt alle 2 Sekunden die Liste der geöffneten FDS an, nicht die auf stdout ausgegebenen Inhalte .
Ángel
Ángel, stimmt. Er könnte die Uhr mit einer Katze benutzen, um das Ergebnis zu sehen, auf welchem ​​Deskriptor er überwachen möchte. Ich denke @ Peter-Horvath, gab die perfekte Erklärung für die Frage.
Jayesh
Ich weiß watch. Ich versuche, die Ausgabe des bereits ausgeführten Prozesses zu überprüfen, was watchnicht hilft.
cprn