Wie kann die Standardeingabe eines Programms als Argument an ein anderes übergeben werden?

17

Angenommen, ein Programm besteht aus zwei Argumenten. Eingabedatei und Ausgabedatei.

Was ist, wenn ich diese Ausgabedatei nicht auf der Festplatte speichern, sondern direkt an ein stdinanderes Programm übergeben möchte? Gibt es einen Weg, dies zu erreichen?

Viele Befehle, auf die ich unter Linux stoße, bieten die Option, '-' als Ausgabedatei-Argument zu übergeben, was genau das tut, was ich oben angegeben habe. Liegt das daran, dass die Weitergabe stdineines Programms als Argument nicht möglich ist? Wenn ja, wie machen wir das?

Ein Beispiel für die Verwendung dieses Bilds ist:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" stdin(echo)

Die Shell, die ich benutze, ist bash.

Dziugas
quelle
1
cat <file | cmd /dev/fd/0funktioniert bei den meisten einheiten.
mikeserv
Ich arbeite nicht für mich. Versucht es mit: cat < README.txt | cp /dev/fd/0. Es hießcp: missing destination file operand after ‘/dev/fd/0’ Try 'cp --help' for more information.
Dziugas
1
program input-file /dev/stdout | another-program? Beachten Sie auch, dass echonichts von stdin liest.
Yaegashi
1
@Dziugas - natürlich nicht - Sie können keine cpDatei nirgendwo. echo 1 2 3| cp /dev/fd/0 /dev/ttywird gedruckt 1 2 3. Und übrigens /dev/fd/[num]ist eher zu arbeiten als /dev/std(in|out|err)in den meisten Fällen. Unter Portabilität von Dateideskriptor-Links erfahren Sie, was Sie wo erwarten können.
mikeserv
1
Ein gutes UNIX-Programm würde in die Standardausgabe schreiben und es dem Benutzer überlassen, zu entscheiden, ob er zu einer Datei umleiten oder zu einem anderen Befehl umleiten möchte.
Jorge Bucaran

Antworten:

13

Wenn das Programm das Schreiben in einen beliebigen Dateideskriptor unterstützt, auch wenn es nicht suchen kann, können Sie ihn /dev/stdoutals Ausgabedatei verwenden. Dies ist ein Symlink zu /proc/self/fd/1meinem System. Dateideskriptor 1 ist stdout.

TiCPU
quelle
Dies löste meine Frage. Gibt es also keine Möglichkeit, dies zu tun, wenn das Programm danach suchen muss?
Dziugas
3
Wenn Sie versuchen, den Datenträgerzugriff zu verhindern, können Sie die Datei in / dev / shm / schreiben. Wenn Sie jedoch keine Datei im Dateisystem haben möchten, können Sie meines Wissens nach nicht danach suchen ein Rohr. Vorwärts suchen bedeutet, dass es alles im Speicher puffern muss, bis es diesen Punkt vorwärts erreicht, und rückwärts suchen bedeutet, alles im Speicher gepuffert zu haben.
TiCPU,
pdftotextWie viele (aber nicht alle) andere Dienstprogramme auch, die dies unterstützen -(was sogar auf Systemen funktionieren würde, die / dev / stdout nicht unterstützen, oder auf denen / dev / stdout nicht wie erwartet funktioniert, wie unter Linux, wo stdout nicht funktioniert ein Rohr). pdftotext file.pdf - | wc -c
Stéphane Chazelas
11

Von der pdftotextManpage:

Wenn die Textdatei ´- 'ist, wird der Text an stdout gesendet.

In diesem Fall brauchen Sie also nur:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" -

Oder wenn Sie dies an STDIN eines anderen Programms leiten möchten:

pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" - | another_prog

Die Verwendung -als Ersatz für einen Dateinamen ist eine Konvention, der viele Dienstprogramme folgen (einschließlich pdftotext), wenn wir eine Eingabe von STDIN oder eine Ausgabe an STDOUT wünschen. Es folgen jedoch nicht alle Dienstprogramme dieser Konvention. In diesem Fall besteht der idiomatische Weg, dies in bash zu tun, in der Verwendung einer Prozesssubstitution :

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( cat )

Hier >( )verhält sich das weitgehend wie eine Datei, an die übergeben wird my_utility, aber anstatt eine echte Datei zu sein, wird der Stream in den Standard des enthaltenen Prozesses geleitet, dh cat. Hier sollte der Text also letztendlich nach Bedarf ausgegeben werden.

Die Verwendung von UUOC löstcat in solchen Foren fast immer Alarmglocken aus . Ich behaupte, dass, wenn das Dienstprogramm nicht unterstützt -, dies eine nützliche Verwendung von catist. Wenn es jedoch Möglichkeiten gibt, diese Prozessersetzung ohne das zu tun cat, dann bin ich ganz Ohr ;-).

Wenn jedoch (wie in der Frage angegeben) das endgültige Ziel des Streams STDIN eines anderen Programms ist, catkann Folgendes beseitigt werden:

my_utility "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf" >( another_prog )
Digitales Trauma
quelle
2
Und lassen Sie mich noch einmal rückgängig machen: Wenn prog2auf stdout geschrieben wird, ist dies besser als , da das Formular auf das Ausfüllen wartet (dh bevor die Shell die nächste Eingabeaufforderung ausgibt oder zum nächsten Befehl übergeht (z. B. nach oder )), während die -less Formular wartet nur auf das Ausfüllen . Nach dem Formular befindet sich auch der Beendigungsstatus von , wohingegen in dem anderen der Beendigungsstatus von ist . (Sie zahlen Ihr Geld und Sie treffen Ihre Wahl.)prog1 input_file >( cat ) | prog2prog1 input_file >( prog2 )catprog2;&&catprog1cat$?prog2$?prog1
Scott
4

Wenn Ihre Shell sie unterstützt, ist die einfachste Möglichkeit, solche Manipulationen durchzuführen, die Verwendung der Prozessersetzung : <(…)und >(…). Dies funktioniert in bash, zsh und ksh und möglicherweise auch in anderen Shells. Beispielsweise:

$ sort <(printf "b\nc\na\n")
a
b
c
$ ls
foo
$ cp <(find . -name foo) bar
$ ls
bar  foo

Dies ist jedoch in dem von Ihnen angegebenen Beispiel nicht hilfreich, da pdftotextes in einer Textdatei gespeichert wird. Während Ihre beste Wahl (abgesehen von der offensichtlichen Verwendung -) /dev/stdoutdie von @TiCPU vorgeschlagene Verwendung ist, können Sie auch eine andere Shell-Funktion verwenden. Das Konstrukt !:Nverweist auf das N-te Argument des vorherigen Befehls. Daher können Sie Folgendes tun:

$ pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf"  out.txt
$ cat !:2
terdon
quelle
1
Ich bin damit einverstanden, dass cat <()dies in einigen Situationen nützlich sein kann, aber in diesem Szenario funktioniert es überhaupt nicht. Das Problem (das von OP sehr schlecht beschrieben wird, muss ich zugeben) besteht darin, dass pdftotextzwei Argumente erforderlich sind : Eingabedatei und Ausgabedatei . Wenn das zweite Argument fehlt, wird nichts erzeugt, und cat <(pdftotext "file.pdf")es wird auch nichts zurückgegeben. Man kann das pdftotextKommando betrügen, indem man >(cat)als zweites Argument wie Digitales Trauma antwortet, aber hier cat <()ist es sinnlos. Für den pdftotextFall, dass es am besten ist, nur den -Namen der Ausgabedatei zu verwenden.
Jimmy
1
@Scott Wie ist meine Antwort ein UUOC? Wie würden Sie diesen Prozessersatz ohne Katze durchführen? >( )leitet den Stream effektiv an den Prozess weiter, der sich im Inneren befindet. Wir benötigen also ein catHere, um diesen Stream auszugeben. Normalerweise sollten wir in der Lage sein, so etwas zu tun pdftotext input.pdf -, aber anscheinend pdftotextunterstützt es nicht den -Parameter, direkt auf stdout anstatt auf eine Datei auszugeben - probieren Sie es aus.
Digital Trauma
1
@DigitalTrauma es ist nicht uuoc. Ich glaube, dass cat die schnellste ist, die Sie erhalten können, wenn Sie nur drucken, aber tatsächlich können Sie einen anderen Befehl verwenden >(grep something), um nützlicher zu sein. BTW, meine pdftotext 3.04 do Unterstützung -als Ausgabedatei, so dass ich ein wenig bin überrascht von der ganzen Diskussion.
Jimmy
1
@terdon Ich hasse es, ein Stickler zu sein, aber das scheint nicht zu funktionieren. Insbesondere unterscheidet es sich nicht von der Ausführung pdftotext "C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.pdf", bei der die Ausgabe in eine Datei mit dem Namen gestellt wird C BY BRIAN W KERNIGHAN & DENNIS M RITCHIE.txt, aber der Text wird nicht an STDOUT ausgegeben, um an ein anderes Programm weitergeleitet zu werden.
Digital Trauma
1
@DigitalTrauma das ist kein stickler! Ich bin ein Idiot. Vielen Dank für den Hinweis und bitte entschuldigen Sie sich nie, wenn Sie auf Fehler hinweisen. Mir wäre es viel lieber, wenn ich auf meinen Fehler hingewiesen würde und so etwas lerne, als es in all seiner zweifelhaften Pracht dort zu belassen.
Terdon
-2
cmd tty

ttyGibt den Namen des Terminals zurück, mit dem verbunden ist stdout.

jas
quelle
Ich bin nicht sicher, wie dies die Frage beantwortet, bei der es um das Kombinieren von Befehlen geht. Vielleicht erweitern Sie mit einem Beispiel, wie Sie das erreichen würden.
Dhag
Ich vermute, Sie sagen, Sie sollten nach ttydem Namen des Terminals suchen und diese Datei dann beispielsweise als Ausgabe verwenden pdftotext file.pdf /dev/pts/2. In diesem Fall stimme ich zu.
Jimmy
Das kann abgekürzt / automatisiert werden ; das wird in der Regel gleichwertig sein mit . Aber dieser Ansatz geht davon aus, dass das Ziel ist , die Ausgabe angezeigt werden (dh im Terminal), und das ist nicht das, was die Frage stellt (siehe die Kommentare auf terdon Antwort für einige Aufklärung über die Bedeutung der Frage). prog1  input_file $(tty)prog1  input_file /dev/ttyprog1
Scott