Comment envoyer des caractères à une commande comme s'ils venaient d'un fichier?

22

Comment envoyer des caractères à une commande comme s'ils venaient d'un fichier?

Par exemple, j'ai essayé:

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

Réponses:

32

Dans les shells qui prennent en charge ici les chaînes , y compris bash, zshet ksh93, vous pouvez utiliser

wc <<< "apple pear orange"
tournevis
la source
@Kusalananda thanks - J'ai édité vos informations dans
steeldriver
18

Deux autres approches (qui permettent une entrée sur plusieurs lignes sans effort supplémentaire):

  1. Utilisez un "document ici":

    $ wc << EOF
    pomme poire orange
    EOF
      1 3 18
    $

    La EOFchaîne est un délimiteur. Vous pouvez utiliser n'importe quelle chaîne; EOFest juste un choix conventionnel.

  2. Utilisez le tty comme entrée:

    $ wc
    pomme poire orange
    Ctrl+D
      1 3 18
    $

    Cela présente l'inconvénient que le programme démarre et démarre la lecture de l'entrée dès que vous tapez son nom. Cela peut être déconcertant; par exemple:

    $ grep v
    Le renard brun rapide              (tapé) 
    saute                       (tapé) 
    saute                       (c'est la sortie de grep!) 
    Le chien paresseux.                   (tapé)
    Ctrl + D
                                    (Pas de sortie ici) 
    $
G-Man dit «Réintègre Monica»
la source
Pour mémoire: Le <<<formulaire permet également la saisie sur plusieurs lignes sans effort supplémentaire, car la "chaîne -enclosed peut contenir des retours à la ligne. Bien sûr, le << EOFformulaire (la syntaxe originale ici-doc) est plus facile à lire si vous avez une entrée sur plusieurs lignes.
alexis
La page de manuel dit qu'ici la syntaxe des chaînes est <<< word- bien sûr, dans le contexte du shell, a wordpeut être une chaîne entre guillemets, contenant des espaces et des retours à la ligne! Oh! C'est tellement évident que cela va sans dire (et, en fait, je ne le vois pas du tout mentionné dans la page de manuel). :-( Merci de me l'avoir signalé!
G-Man dit 'Reinstate Monica'
Je n'appellerais pas ça simple ou évident, vraiment. A wordest défini dans la page de manuel comme "Une séquence de caractères considérée comme une seule unité par le shell" (aka "token"), et vous devez savoir que les chaînes entre guillemets sont traitées comme "une seule unité" dans le sens pertinent (après traitement de barre oblique inverse, expansion variable, etc. "Mais en fait, c'est tout le but des guillemets doubles dans le shell. (Les guillemets simples protègent également contre l'expansion.) Le modèle de traitement du shell est très bien pensé et tout sauf simple.
alexis
@alexis: Quand je vais au-dessus comme ça et que j'inclus une émoticône, il faut considérer la possibilité que je sois ironique.
G-Man dit `` Réintègre Monica '' le
10

Bien qu'il existe plusieurs solutions valides ici, une autre syntaxe qui peut parfois être utile consiste à exécuter une commande dans <(). Cela vous permettrait de créer plus d'un objet descripteur de fichier sur une ligne de commande.

Cela peut être utile lorsque vous faites quelque chose comme comparer de longues chaînes de texte ou si vous souhaitez différencier du contenu qui ne se trouve pas dans un fichier.

Par exemple, en comparant les fichiers hôtes sur deux nœuds sans avoir à copier le fichier hôtes sur l'hôte local:

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

Le <redirige un fichier vers STDIN et ()crée un sous-shell pour exécuter la commande entre parenthèses. C'est le STDOUT du sous-shell qui est passé à STDIN de la commande en cours d'exécution.

C'est un moyen plus facile de créer plus d'un "fichier" d'entrée pour une commande que d'essayer d'utiliser plusieurs documents ici ou d'essayer de faire écho à plusieurs commandes d'un pipeline vers la commande finale.

Tim Kennedy
la source
<fileorpathnameredirige stdin, mais <(subcmd)ne le fait pas; il remplace un nom qui, lorsqu'il est ouvert par le programme, peut lire stdout depuis subcmd. < <(subcmd)(espace requis) redirige stdin de ce fichier, presque comme subcmd |. Vous diffpouvez lire l' une de ses entrées depuis stdin en spécifiant un argument de -mais pas les deux.
dave_thompson_085
C'est la substitution de processus qui n'est pas prise en charge, contrairement aux pièces que vous prétendez être fabriquées (mais ce n'est pas comme expliqué).
phk
1
Mon diff fonctionne très bien en bash sur les systèmes Ubuntu 16.04 et Solaris 11.2 avec lesquels je dois tester. Il est possible que cela ne fonctionne pas pour tous les shells sur tous les systèmes d'exploitation. Il s'agit en fait de créer des descripteurs de fichiers qui peuvent être utilisés pour lire la sortie du sous-processus comme s'il lisait un fichier. Étant donné que diff prend deux arguments de fichier, il est capable de lire la sortie des deux sous-processus via les descripteurs de fichier créés et de les comparer.
Tim Kennedy le
Vous souhaiterez peut-être ajouter à votre réponse la différence entre cmd <(cmd2 ...)et cmd < <(cmd2 ...). Le premier permet aux données dérivées (la sortie de cmd2) d'être utilisées à la place d'un nom de fichier. Ce dernier est équivalent à cmd2 ... | cmd. Les commandes doivent être écrites pour accepter explicitement l'entrée stdin et beaucoup ne le sont pas. Cela est particulièrement vrai pour les scripts shell.
DocSalvager
8

vous pouvez utiliser un tuyau

echo "apple pear orange" | wc
Slh47
la source
8
Un tuyau n'est pas la même chose que "lire un fichier". Par exemple, vous ne pouvez pas rechercher en arrière dans un canal, alors que vous pouvez le faire dans un fichier.
rbialon
0

Vous voudrez peut-être utiliser quelque chose de similaire à attendre. Voici un exemple simple d'ouverture d'une session Telnet distante, d'attente de l'invite, d'envoi de données, d'attente d'une réponse, de mise en veille et de sortie.

#!/usr/bin/expect
spawn telnet localhost 8555
expect "Escape character is '^]'."
send "Hello World\n"
expect "Connection closed by foreign host."
sleep 1
Lâche anonyme
la source