Pseudodateien für temporäre Daten

98

Ich möchte häufig relativ kurze Zeichenfolgendaten (kann aber auch mehrere Zeilen umfassen) an Befehlszeilenprogramme übergeben, die wiederholt nur Eingaben aus Dateien (z. B. wdiff) akzeptieren. Sicher kann ich eine oder mehrere temporäre Dateien erstellen, die Zeichenfolge dort speichern und den Befehl mit dem Dateinamen als Parameter ausführen. Es sieht für mich jedoch so aus, als wäre dieses Verfahren äußerst ineffizient, wenn Daten tatsächlich auf die Festplatte geschrieben würden, und es könnte die Festplatte mehr als schädigen, wenn ich dieses Verfahren viele Male wiederhole, z. B. wenn ich einzelne Zeilen langen Textes einspeisen möchte Dateien zu wdiff. Gibt es eine empfohlene Möglichkeit, dies zu umgehen, indem beispielsweise Pseudodateien wie Pipes zum temporären Speichern der Daten verwendet werden, ohne sie tatsächlich auf die Festplatte zu schreiben (oder nur, wenn sie eine kritische Länge überschreiten). Beachten Sie, dass wdiff zwei Argumente akzeptiert undwdiff <"text".

highsciguy
quelle
Kann dies über gelöst werden xargs?
NN
Weiß nicht, aber es wäre mir nicht klar, wie. Soweit ich weiß, xargswürden die Eingabezeilen aus den Datei-String-Argumenten für den Befehl bestehen. Aber ich brauche das Gegenteil.
Highsciguy
@rahmu Ich habe es mir angesehen, aber ich denke, die Problemeinstellung ist dort etwas anders. Zumindest sehe ich nicht, wie die Antworten helfen würden. Die akzeptierte Antwort, um temporäre Dateien korrekt zu erstellen, ist im Wesentlichen das, was ich nicht vermeiden möchte, wenn nicht eine Art Puffer vorhanden ist, der das Schreiben der Dateien tatsächlich verhindert. Ich habe nur begrenzte Kenntnisse darüber, wie die temporären Dateien funktionieren!
Highsciguy
Was ist los mit echo $data_are_here | dumb_program?
Vonbrand
1
Dies würde nur eine Eingabedatei unterstützen und nicht alle Programme würden von stdin lesen.
Highsciguy

Antworten:

55

Verwenden Sie eine Named Pipe . Zur Veranschaulichung:

mkfifo fifo
echo -e "hello world\nnext line\nline 3" > fifo

Das -eTells-Echo interpretiert das Newline-Escape ( \n) richtig . Dies blockiert, dh Ihre Shell bleibt hängen, bis etwas die Daten aus der Pipe liest.

Öffnen Sie eine andere Shell irgendwo und im selben Verzeichnis:

cat fifo

Sie werden das Echo lesen, das die andere Shell freigibt. Obwohl die Pipe als Dateiknoten auf der Festplatte vorhanden ist, werden die Daten, die sie passieren, nicht übertragen. alles spielt sich im Gedächtnis ab. Sie können &das Echo im Hintergrund ( ) anzeigen.

Die Pipe verfügt über einen 64-KB-Puffer (unter Linux) und blockiert wie ein Socket den Writer, wenn er voll ist, sodass Sie keine Daten verlieren, solange Sie den Writer nicht vorzeitig beenden.

Goldlöckchen
quelle
Ok, danke, das funktioniert auch mit zwei Named Pipes und wdiff. Aber ich dachte zu verstehen, dass eine bestimmte (kleine) Menge an Speicher für die Pipe als Puffer verfügbar ist. Was passiert, wenn ich die Puffergröße überschreite?
Highsciguy
Ich habe einen letzten Absatz zu diesem Thema hinzugefügt.
Goldlöckchen
3
/tmpwird in den meisten Distributionen so konfiguriert, dass ein tmpfsDateisystem im RAM verwendet wird. Wenn Sie eine Datei /tmpdarin schreiben, wird sie direkt in Ihren Arbeitsspeicher geschrieben. Dies ist eine gute Antwort für semi-ausfallsichere Dateien, auf die schnell zugegriffen und viele Male neu geschrieben werden muss.
129

In Bash können Sie die command1 <( command0 )Umleitungssyntax verwenden, die die command0stdout umleitet und an eine übergibt command1, die einen Dateinamen als Befehlszeilenargument verwendet. Dies wird als Prozesssubstitution bezeichnet .

Einige Programme, die Dateinamen-Befehlszeilenargumente verwenden, benötigen eine echte Direktzugriffsdatei, daher funktioniert diese Technik bei diesen Programmen nicht. Es funktioniert jedoch gut mit wdiff:

user@host:/path$ wdiff <( echo hello; echo hello1 ) <( echo hello; echo hello2 )
hello
[-hello1-]
{+hello2+}

Im Hintergrund wird ein FIFO erstellt, der Befehl innerhalb <( )des FIFO weitergeleitet und der Dateideskriptor des FIFO als Argument übergeben. Um zu sehen, was los ist, versuchen Sie es mit echo, um das Argument zu drucken, ohne etwas damit zu tun:

user@host:/path$ echo <( echo hello )
/dev/fd/63

Das Erstellen einer Named Pipe ist flexibler (wenn Sie eine komplizierte Umleitungslogik mit mehreren Prozessen schreiben möchten), aber für viele Zwecke ist dies ausreichend und offensichtlich einfacher zu handhaben.

Es gibt auch die >( )Syntax, wann Sie sie als Ausgabe verwenden möchten, z

$ someprogram --logfile >( gzip > out.log.gz )

Siehe auch das Spickzettel für Bash-Umleitungen für verwandte Techniken.

Mechanische Schnecke
quelle
Dies wird in KSH
chanchal1987
5
ksh hat das erfunden. Sie verwenden eine Variante von ksh, die es nicht unterstützt
Neil McGuigan
2
Einige Programme, die Dateinamen-Befehlszeilenargumente verwenden, benötigen eine echte Direktzugriffsdatei, daher funktioniert diese Technik bei diesen Programmen nicht. Was machen Sie in diesen Fällen? Wäre zum Beispiel ssh -F <(vagrant ssh-config) defaultecht nett aber leider.
Sukima
10

wdiff ist ein Sonderfall, da 2 Dateinamenargumente erforderlich sind. Für alle Befehle, die nur 1 Argument benötigen und die hartnäckig ablehnen, etwas anderes als ein Dateinamenargument zu verwenden, gibt es 2 Optionen:

  • Der Dateiname '-' (dh ein Minuszeichen) funktioniert ungefähr die Hälfte der Zeit. Es scheint davon abzuhängen, um welchen Befehl es sich handelt und ob der Entwickler des Befehls diesen Fall abfängt und wie erwartet behandelt. z.B

    $> ls | Katze -

  • Es gibt eine psuedo-Datei mit dem Namen / dev / stdin, die unter Linux existiert und verwendet werden kann, wenn ein Befehl unbedingt einen Dateinamen erfordert. Dies funktioniert mit größerer Wahrscheinlichkeit, da für den Befehl keine spezielle Behandlung von Dateinamen erforderlich ist. Wenn ein FIFO funktioniert oder die Bash- Prozess-Substitutionsmethode funktioniert, sollte dies auch funktionieren und ist nicht Shell-spezifisch. z.B

    $> ls | cat / dev / stdin

dabuntu
quelle
1
less und openssl like / dev / stdin anstatt / dev / fd / NUM :-)
eel ghEEz