Come posso inviare caratteri a un comando come se provenissero da un file?


22

Come posso inviare caratteri a un comando come se provenissero da un file?

Ad esempio ho provato:

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

Risposte:



18

Altri due approcci (che consentono input su più righe senza sforzo aggiuntivo):

  1. Usa un "documento qui":

    $ wc << EOF
    mela pera arancia
    EOF
      1 3 18
    $

    La EOFstringa è un delimitatore. Puoi usare qualsiasi stringa; EOFè solo una scelta convenzionale.

  2. Usa tty come input:

    $ wc
    mela pera arancia
    Ctrl+D
      1 3 18
    $

    Questo ha lo svantaggio che il programma inizia a funzionare e inizia a leggere l'input, non appena si digita il suo nome. Questo può essere sconcertante; per esempio:

    $ grep v
    La rapida volpe marrone              (dattiloscritta) 
    salta                       (dattiloscritta) 
    salta sopra                       (Questo è prodotto da grep!) ​​Il 
    cane pigro.                   (digitato)
    Ctrl + D
                                    (Nessun output qui) 
    $

Per la cronaca: il <<<modulo consente anche l'inserimento di più righe senza ulteriore sforzo, poiché la "stringa racchiusa può contenere nuove righe. Naturalmente il << EOFmodulo (la sintassi here-doc originale) è più facile da leggere se si dispone di input multilinea.
alexis

La pagina man dice che qui la sintassi delle stringhe è <<< word- ovviamente, nel contesto della shell, a wordpuò essere una stringa tra virgolette, contenente spazi e newline! D'oh! È così ovvio che è ovvio (e, in effetti, non lo vedo menzionato nella pagina man). :-( Grazie per avermelo fatto notare!
G-Man dice 'Reinstate Monica' il

Non lo definirei semplice o ovvio, davvero. A wordè definito nella manpage come "Una sequenza di caratteri considerata come una singola unità dalla shell" (aka "token"), e devi sapere che le stringhe tra virgolette sono trattate come "una singola unità" nel senso rilevante (dopo elaborazione di barre rovesciate, espansione variabile ecc. "Ma in effetti questo è l'intero scopo della doppia virgoletta nella shell. (Le virgolette singole proteggono anche dall'espansione.) Il modello di elaborazione della shell è molto ben pensato e tutt'altro che semplice.
alexis

@alexis: quando esco in quel modo e includo un'emoticon, si dovrebbe considerare la possibilità che io sia ironico.
G-Man dice "Ripristina Monica" il

10

Sebbene ci siano diverse soluzioni valide qui, un'altra sintassi che può essere utile a volte è quella di eseguire un comando <(). Ciò consentirebbe di creare più di 1 oggetto descrittore di file su una riga di comando.

Questo può essere utile quando stai facendo qualcosa come confrontare lunghe stringhe di testo, o se vuoi diff un po 'di contenuto che non è in un file.

Ad esempio, confrontando i file hosts su due nodi senza dover copiare il file hosts su localhost:

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

Il <reindirizza un file per STDIN, e il ()creare una subshell per eseguire il comando tra parentesi. È lo STDOUT della subshell che viene passato a STDIN del comando in esecuzione.

È un modo più semplice per creare più di 1 "file" di input in un comando piuttosto che provare a utilizzare più documenti qui o provare a inviare più comandi a una pipeline al comando finale.


<fileorpathnamereindirizza stdin, ma <(subcmd)non lo fa; sostituisce un nome che quando / se aperto dal programma può leggere stdout da subcmd. < <(subcmd)(spazio richiesto) reindirizza lo stdin da quel file, quasi come subcmd |. Potresti diffleggere uno dei suoi input da stdin specificando un argomento di -ma non entrambi.
dave_thompson_085,

Questa è la sostituzione del processo che non è supportata, a differenza delle parti che affermi che siano state cancellate (ma non è come spiegato da Dave).
phk,

1
Il mio diff funziona perfettamente su Ubuntu 16.04 e sui sistemi Solaris 11.2 con cui devo provare. È possibile che potrebbe non funzionare per tutte le shell su tutti i sistemi operativi. In realtà sta creando descrittori di file che possono essere utilizzati per leggere l'output dal sottoprocesso come se stesse leggendo un file. Poiché diff accetta due argomenti di file, è in grado di leggere l'output di entrambi i sottoprocessi attraverso i descrittori di file creati e confrontarli.
Tim Kennedy,

Potresti voler aggiungere alla tua risposta la differenza tra cmd <(cmd2 ...)e cmd < <(cmd2 ...). Il primo consente di utilizzare i dati derivati ​​(output di cmd2) al posto di un nome file. Quest'ultimo è equivalente a cmd2 ... | cmd. I comandi devono essere scritti per accettare esplicitamente l'input stdin e molti non lo sono. Ciò è particolarmente vero per gli script di shell.
DocSalvager,

8

puoi usare una pipa

echo "apple pear orange" | wc

8
Una pipe non è la stessa di "lettura da un file". Ad esempio, non è possibile cercare all'indietro in una pipe, mentre è possibile in un file.
rbialon,

0

Potresti voler usare qualcosa di simile ad aspettarti. Di seguito è riportato un semplice esempio di apertura di una sessione telnet remota, in attesa del prompt, invio di alcuni dati, attesa di una risposta, sospensione e chiusura.

#!/usr/bin/expect
spawn telnet localhost 8555
expect "Escape character is '^]'."
send "Hello World\n"
expect "Connection closed by foreign host."
sleep 1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.