Wie kann ich Zeichen an einen Befehl senden, als stammten sie aus einer Datei?

22

Wie kann ich Zeichen an einen Befehl senden, als stammten sie aus einer Datei?

Zum Beispiel habe ich versucht:

wc < "apple pear orange"
-bash: apple pear orange: No such file or directory
Tyler Durden
quelle

Antworten:

32

In Schalen , die Unterstützung hier Strings , einschließlich bash, zshund ksh93können Sie verwenden

wc <<< "apple pear orange"
Stahlfahrer
quelle
@ Kusalananda danke - ich habe deine Info in bearbeitet
steeldriver
18

Zwei weitere Ansätze (die eine mehrzeilige Eingabe ohne zusätzlichen Aufwand ermöglichen):

  1. Verwenden Sie ein "hier Dokument":

    $ wc << EOF
    Apfel Birne Orange
    EOF
      1 3 18
    $

    Die EOFZeichenfolge ist ein Begrenzer. Sie können eine beliebige Zeichenfolge verwenden. EOFist nur eine konventionelle Wahl.

  2. Verwenden Sie das tty als Eingabe:

    $ wc
    Apfel Birne Orange
    Ctrl+D
      1 3 18
    $

    Dies hat den Nachteil, dass das Programm zu starten beginnt und die Eingabe liest, sobald Sie den Namen eingeben. Dies kann beunruhigend sein. beispielsweise:

    $ grep v
    Der schnelle braune Fuchs              (getippt) 
    springt über                       (getippt) 
    springt über                       (Dies wird von grep ausgegeben!) 
    Den faulen Hund.                   (getippt)
    Ctrl + D
                                    (Keine Ausgabe hier) 
    $
G-Man sagt, "Monica wiedereinsetzen"
quelle
Für den Datensatz: Das <<<Formular ermöglicht auch die Eingabe mehrerer Zeilen ohne zusätzlichen Aufwand, da die "eingeschlossene Zeichenfolge Zeilenumbrüche enthalten kann. Natürlich ist das << EOFFormular (die ursprüngliche Here-Doc-Syntax) leichter zu lesen, wenn Sie mehrzeilige Eingaben haben.
Alexis
Die Manpage sagt, dass hier die String-Syntax ist <<< word- natürlich kann im Kontext der Shell wordein String in Anführungszeichen stehen, der Leerzeichen und Zeilenumbrüche enthält! D'oh! Das ist so offensichtlich, dass es selbstverständlich ist (und tatsächlich sehe ich es überhaupt nicht in der Manpage erwähnt). :-( Danke, dass du mich darauf hingewiesen hast!
G-Man sagt, dass Monica am
Ich würde es nicht einfach oder offensichtlich nennen. A wordist in der Manpage als "Eine Zeichenfolge, die von der Shell als eine Einheit betrachtet wird" (auch "Token" genannt) definiert. Sie müssen wissen, dass Zeichenfolgen in Anführungszeichen im relevanten Sinne (nach "eine Einheit") als "eine Einheit" behandelt werden Backslash-Verarbeitung, variable Erweiterung usw. "Aber genau das ist der Zweck der doppelten Anführungszeichen in der Shell. (Einfache Anführungszeichen schützen auch vor Erweiterung.) Das Verarbeitungsmodell der Shell ist sehr gut durchdacht und alles andere als einfach.
alexis
@alexis: Wenn ich so übertreibe und ein Emoticon einbinde , sollte man die Möglichkeit in Betracht ziehen, dass ich ironisch bin.
G-Man sagt, dass Monica
10

Obwohl es hier mehrere gültige Lösungen gibt, ist es eine andere Syntax, die manchmal nützlich sein kann, einen Befehl auszuführen <(). Auf diese Weise können Sie mehr als ein Dateideskriptorobjekt in einer Befehlszeile erstellen.

Dies kann nützlich sein, wenn Sie beispielsweise lange Textfolgen vergleichen oder Inhalte, die sich nicht in einer Datei befinden, vergleichen möchten.

Vergleichen Sie beispielsweise die Hosts-Dateien auf zwei Knoten, ohne die Hosts-Datei auf den localhost kopieren zu müssen:

diff -Naur <(cat /etc/hosts) <(ssh -q otherhost 'cat /etc/hosts')

Das <leitet eine Datei zu STDIN um und das ()erstellt eine Subshell, um den Befehl zwischen den Klammern auszuführen. Es ist das STDOUT aus der Subshell, das an STDIN des ausgeführten Befehls übergeben wird.

Es ist eine einfachere Möglichkeit, mehr als eine Eingabe- "Datei" für einen Befehl zu erstellen, als zu versuchen, mehrere Dokumente hier zu verwenden oder mehrere Befehle an eine Pipeline zum endgültigen Befehl zurückzugeben.

Tim Kennedy
quelle
<fileorpathnameleitet stdin um, <(subcmd)tut es aber nicht; Es ersetzt einen Namen, der beim Öffnen durch das Programm stdout von subcmd lesen kann. < <(subcmd)(Platz benötigt) leitet stdin von dieser Datei fast wie um subcmd |. Sie diffkönnen eine der Eingaben von stdin lesen, indem Sie ein Argument von -aber nicht von beiden angeben .
Dave_thompson_085
Dies ist eine Prozessersetzung, die nicht unterstützt wird, im Gegensatz zu den Teilen, von denen Sie behaupten, dass sie abgeschnitten ist (aber nicht so, wie es Dave erklärt hat).
Phk
1
Mein Diff funktioniert gut in Bash auf Ubuntu 16.04 und Solaris 11.2 Systemen, mit denen ich testen muss. Möglicherweise funktioniert es nicht für alle Shells unter allen Betriebssystemen. Tatsächlich werden Dateideskriptoren erstellt, mit denen die Ausgabe des Unterprozesses so gelesen werden kann, als würde eine Datei gelesen. Da diff zwei Dateiargumente akzeptiert, kann es die Ausgabe beider Unterprozesse durch die erstellten Dateideskriptoren lesen und vergleichen.
Tim Kennedy
Möglicherweise möchten Sie zu Ihrer Antwort den Unterschied zwischen cmd <(cmd2 ...)und hinzufügen cmd < <(cmd2 ...). Ersteres ermöglicht es, abgeleitete Daten (die Ausgabe von cmd2) anstelle eines Dateinamens zu verwenden. Letzteres ist äquivalent zu cmd2 ... | cmd. Befehle müssen geschrieben werden, um stdin-Eingaben explizit zu akzeptieren, viele jedoch nicht. Dies gilt insbesondere für Shell-Skripte.
DocSalvager
8

Sie können eine Pfeife verwenden

echo "apple pear orange" | wc
Slh47
quelle
8
Eine Pipe ist nicht dasselbe wie "Lesen aus einer Datei". Zum Beispiel können Sie in einer Pipe nicht rückwärts suchen, während Sie dies in einer Datei können.
RBIALON
0

Möglicherweise möchten Sie etwas Ähnliches verwenden. Im Folgenden finden Sie ein einfaches Beispiel für das Öffnen einer Remote-Telnet-Sitzung, das Warten auf die Eingabeaufforderung, das Senden einiger Daten, das Warten auf eine Antwort, den Ruhezustand und das Beenden.

#!/usr/bin/expect
spawn telnet localhost 8555
expect "Escape character is '^]'."
send "Hello World\n"
expect "Connection closed by foreign host."
sleep 1
Anonymer Feigling
quelle