Übergeben Sie Text an das Programm, das eine Datei erwartet

30

Im Zusammenhang mit einer Frage zu Stack Overflow: Mehrere Codezeilen an wsadmin.sh übergeben? .

Ich habe als Zeichenfolge ein paar Eingabezeilen, die ich in einen Befehl eingeben muss. Der Befehl akzeptiert jedoch nur eine Datei voller Eingaben.

Gibt es eine Möglichkeit, die Zeilen in einer temporären Datei oder Pipe zu speichern, die eigentlich nie auf die Festplatte geschrieben wird, und diese dann direkt in das Programm einzuspeisen?

Wie kann ich die Pipe erfassen, die Eingabe in sie einspeisen, die Pipe an den Befehl übergeben und dann die Pipe entfernen?

ArtOfWarfare
quelle
2
Können Sie ein Beispiel für den Befehl hinzufügen, den Sie verwenden, und wie er aufgerufen werden soll?
Durchbruch
2
Heißt das, das Programm akzeptiert kein stdin?
Léo Lam
Ich stimme beiden Kommentatoren zu. Es ist unmöglich, irgendetwas vorzuschlagen, was funktionieren könnte, ohne die Spezifikationen des Programms zu kennen.
Larssend,

Antworten:

27

Eine andere Lösung ist die Verwendung von Process Substitution in Bash. Wenn Ihr System Named Pipes hat, können Sie diese Funktion verwenden.

Es wird wie folgt verwendet:

program_expecting_a_file <(list)

wo listist eine Folge von Shell-Befehlen (eigentlich Pipelines; die vollständigen Details sind hier ). listwird ausgeführt und sein Ausgang wird mit der Pipe verbunden. Der Name der Pipe wird dann an Ihr Programm übergeben.

HINWEIS: Leerzeichen zwischen <und sind nicht zulässig (.

(Die andere Ersetzung >(list)funktioniert ebenfalls wie erwartet.)

In Ihrem speziellen Fall könnten Sie verwenden

program_expecting_a_file <(echo "$your_strings")

obwohl Sie vielleicht finden, dass @ meuhs Lösung eleganter ist.

Update: Eine Vielzahl von Anwendungsbeispielen finden Sie im Advanced Bash Scripting Guide .

Edward
quelle
Die anderen beiden haben auch in den trivialsten Fällen nicht funktioniert. Deiner hat die Tests bestanden, die ich bisher gemacht habe. Ich habe deins fürs Erste upvoted. Ich werde zurückkommen und dies als akzeptiert markieren, wenn es alles tut, was ich brauche.
ArtOfWarfare
Dein funktioniert einwandfrei. Wenn Sie möchten, können Sie es der zugehörigen Frage zu StackOverflow hinzufügen, und ich kann es dort auch akzeptieren. stackoverflow.com/questions/31374202/…
ArtOfWarfare
Hallo @ArtOfWarfare, ich bin froh, Ihnen helfen zu können. Dort drüben gibt es bereits einen Kommentar mit der gleichen vorgeschlagenen Lösung, daher wäre es nicht richtig, dort eine Antwort zu posten.
Edward
Sie haben Ihre Lösung veröffentlicht, bevor er es tat. Wie auch immer, ich habe ihn gebeten, seinen Kommentar in eine Antwort zu ändern, damit ich ihn akzeptieren kann. Wenn keiner von Ihnen innerhalb von 24 Stunden eine Antwort auf diese Frage sendet, schicke ich die Antwort einfach selbst, damit ich sie annehmen kann (ich lasse meine Fragen nicht gerne als unbeantwortet, sobald ich die Antwort gefunden habe. Es ist Nur schlechte Manieren für zukünftige Leser / potenzielle Beantworter der Frage.)
ArtOfWarfare
Hallo @ArtOfWarfare, ich bin absolut in Ordnung mit dem, was Sie vorschlagen!
Edward
15

Sie können ein bash here-doc verwenden . Beispielsweise,

$ cat -n <<<'a
> b'
 1  a
 2  b

Wenn Sie etwas in einer Bash-Variablen haben, können Sie es auch interpolieren: z <<<"path is $PATH".


Wenn Ihr Befehl auf einem Dateinamen besteht, können Sie diesen angeben /dev/stdin. Z.B:

$ sed -f /dev/stdin <<<'s/a/b/'

erzeugt die Ausgabe: s/b/b/.

meuh
quelle
Es ist nicht klar aus der Frage, ob der Befehl Eingaben über akzeptiert stdin, und wenn nicht, wird dies nicht funktionieren. Ich hoffe das OP klärt.
David Z
1
:( - Das schien super vielversprechend, aber als ich es versuchte, bekam ich die Fehlermeldung"-f" option must be followed by a file name.
ArtOfWarfare
Ein Here-Doc ist für stdin. Wenn Ihr Befehl unbedingt -feinen Dateinamen benötigt, geben Sie diesen an /dev/stdin. Siehe meine Bearbeitung.
Meuh
Ich denke, nach den Änderungen ist es absolut eine praktikable Option!
Edward
1
+1 für den /dev/stdinVorschlag. Das Programm, das ich aufzurufen versuche, akzeptiert nur einen Dateinamen, also habe ich es /dev/stdinmit einem Heredoc kombiniert .
Huw Walters
7

Je nachdem, was im Skript enthalten ist, können Sie möglicherweise den speziellen Dateinamen (Minus) verwenden, der für stdin steht

$ mycmd -
Line 1
Line 2
^D

Eine andere Methode, die für Sie funktionieren kann, ist das Öffnen der Datei, /dev/fd/0die wieder für stdin steht .

Eine dritte Möglichkeit kann darin bestehen, ein FIFO (First In First Out) zu erstellen . Das ist wie eine Datei, hat aber zwei Enden: Sie schreiben an ein Ende und lesen vom anderen.

-- Process 1 --                  -- Process 2 --
$ mkfifo foo
$ cat foo
<waits>                          $ echo hello > foo
hello                            $
$ rm foo
Majenko
quelle
3
Es kann erwähnenswert sein, dass das Programm so interpretiert -werden muss - es ist keine Funktion der Shell oder des Betriebssystems. Natürlich folgen die meisten Standard-Linux-Dienstprogramme dieser Konvention, soweit ich weiß.
David Z
1
Nee. Dies funktioniert nicht für das Programm. Es gibt einen interaktiven Modus, aber ich möchte die Befehle, die ausgeführt werden sollen, von einem anderen Programm an dieses Programm übergeben expect.
ArtOfWarfare
@ArtOfWarfare Ich habe gerade eine dritte Option hinzugefügt, die möglicherweise funktioniert.
Majenko
Gute Antwort! Die zweite und dritte Option entsprechen im Grunde der <()Lösung, sind jedoch ausführlicher - was sehr nützlich sein kann!
Edward
4

Es gibt eine andere Option, die der mycmd -Lösung ähnelt , aber auch für Programme, die nicht -speziell behandelt werden:

$ mycmd /dev/stdin
Line 1
Line 2
^D

/dev/stdin scheint mit dem Betriebssystem zu tun zu haben und funktioniert unter Debian GNU / Linux, aber ich bin mir nicht sicher, wo es sonst auch funktionieren wird.

Axel Beckert
quelle
1
Das scheint vielleicht zu funktionieren, aber was ist das ^D?
ArtOfWarfare
^Dist eine gebräuchliche Notation für das Drücken von Strg-D. ^ D hat hier die Semantik "Ende des Eingabestroms". Es ist wahrscheinlich öfter zu sehen in ^Coder ^Zwelche für das Drücken von Strg-C bzw. Strg-Z stehen.
Axel Beckert
1
Das scheint zu funktionieren, aber wie würde ich programmgesteuert Dinge einfügen /dev/stdinund dann schließen?
ArtOfWarfare
1
Leiten Sie einfach etwas in diesen Befehl und es sollte funktionieren, dh cat content | mycmd /dev/stdin. Stellen Sie sich andere Befehle als cathier vor.
Axel Beckert