Envoyer une chaîne à stdin


158

Existe-t-il un moyen de le faire efficacement dans bash:

/my/bash/script < echo 'This string will be sent to stdin.'

Je suis conscient que je pourrais canaliser la sortie de l'écho comme ceci:

echo 'This string will be piped to stdin.' | /my/bash/script

1
Qu'entendez-vous par effectivement , pourquoi la pipe n'est-elle pas un moyen de le faire?
Andy

Les deux commandes que vous avez répertoriées devraient faire exactement la même chose. Quel problème rencontrez-vous?
Flimzy

5
@Flimzy: afaik, le premier ne fonctionnera pas comme prévu, il essaiera d'ouvrir un fichier appeléecho
Andy

Oh oui. Alors, quel est le problème avec la deuxième forme?
Flimzy

2
@Flimzy: de plus, le >formulaire de redirection ouvrira un descripteur de fichier comme fd 0(stdin), alors que |opens démarre un processus enfant et attache son stdout (fd 1) au stdin de l'autre processus. Ce fait peut avoir des conséquences non négligeables (pensez sur le partage des variables d'environnement?)
sehe

Réponses:


262

Vous pouvez utiliser une ligne heredoc

cat <<< "This is coming from the stdin"

ce qui précède est le même que

cat <<EOF
This is coming from the stdin
EOF

ou vous pouvez rediriger la sortie d'une commande, comme

diff <(ls /bin) <(ls /usr/bin)

ou vous pouvez lire comme

while read line
do
   echo =$line=
done < some_file

ou simplement

echo something | read param

Et comment saisir des valeurs binaires de cette manière? Sans utiliser le tuyau (je sais que cela peut être fait avec le tuyau comme suit: echo -e "\x01\x02..." | ./script)
cprcrack

J'aime l'écrire dans l'autre sens: <<< "Ceci vient de stdin" perl ..., de cette façon il ressemble au côté gauche du tube.
Pyrolistique

@Pyrolistique oui! Particulièrement utile lors de la maîtrise par exemple d'un oneliner perl à partir d'une ligne de commande - édition facile des arguments de perl sans avoir besoin de beaucoup de mouvements en arrière avec un curseur. :)
jm666

@ jm666 triste chose, c'est que j'ai appris hier si vous utilisez un alias bash, vous utilisez simplement la forme command_alias <<< "chaîne stdin", sinon il dira commande introuvable
Pyrolistique

@ jm666 Y a-t-il un endroit sur lequel je peux en savoir plus <<<? J'ai honte d'admettre que je ne l'ai jamais vu auparavant, et j'en suis totalement mystifié. J'ai essayé Google pour cela, mais mes résultats sont sans rapport.
wpcarro

66

Tu étais proche

/my/bash/script <<< 'This string will be sent to stdin.'

Pour une entrée multiligne, les here-docs conviennent:

/my/bash/script <<STDIN -o other --options
line 1
line 2
STDIN

Modifier les commentaires:

Pour obtenir une entrée binaire, dites

xxd -r -p <<BINARY | iconv -f UCS-4BE -t UTF-8 | /my/bash/script
0000 79c1 0000 306f 0000 3061 0000 3093 0000 3077 0000 3093 0000 304b 0000 3093 0000 3077 0000 3093 0000 306a 0000 8a71 0000 306b 0000 30ca 0000 30f3 0000 30bb
0000 30f3 0000 30b9 0000 3092 0000 7ffb 0000 8a33 0000 3059 0000 308b 0000 3053 0000 3068 0000 304c 0000 3067 0000 304d 0000 000a
BINARY

Si vous substituez catà /my/bash/script(ou bien laissez tomber le dernier tuyau), cette impression:

私はちんぷんかんぷんな話にナンセンスを翻訳することができ

Ou, si vous vouliez quelque chose d'un peu plus geek:

0000000: 0000 0000 bef9 0e3c 59f8 8e3c 0a71 d63c  .......<Y..<.q.<
0000010: c6f2 0e3d 3eaa 323d 3a5e 563d 090e 7a3d  ...=>.2=:^V=..z=
0000020: 7bdc 8e3d 2aaf a03d b67e b23d c74a c43d  {..=*..=.~.=.J.=
0000030: 0513 d63d 16d7 e73d a296 f93d a8a8 053e  ...=...=...=...>
0000040: 6583 0e3e 5a5b 173e 5b30 203e 3d02 293e  e..>Z[.>[0 >=.)>
0000050: d4d0 313e f39b 3a3e 6f63 433e 1c27 4c3e  ..1>..:>ocC>.'L>
0000060: cde6 543e 59a2 5d3e 9259 663e 4d0c 6f3e  ..T>Y.]>.Yf>M.o>
0000070: 60ba 773e cf31 803e ee83 843e 78d3 883e  `.w>.1.>...>x..>
0000080: 5720 8d3e 766a 913e beb1 953e 1cf6 993e  W .>vj.>...>...>
0000090: 7a37 9e3e c275 a23e dfb0 a63e bce8 aa3e  z7.>.u.>...>...>
00000a0: 441d af3e 624e b33e 017c b73e 0ca6 bb3e  D..>bN.>.|.>...>
00000b0: 6fcc bf3e 15ef c33e e90d c83e d728 cc3e  o..>...>...>.(.>
00000c0: c93f d03e ac52 d43e 6c61 d83e f36b dc3e  .?.>.R.>la.>.k.>
00000d0: 2f72 e03e 0a74 e43e 7171 e83e 506a ec3e  /r.>.t.>qq.>Pj.>
00000e0: 945e f03e 274e f43e f738 f83e f11e fc3e  .^.>'N.>.8.>...>
00000f0: 0000 003f 09ee 013f 89d9 033f 77c2 053f  ...?...?...?w..?
0000100: caa8 073f 788c 093f 776d 0b3f be4b 0d3f  ...?x..?wm.?.K.?
0000110: 4427 0f3f 0000 113f e8d5 123f f3a8 143f  D'.?...?...?...?
0000120: 1879 163f 4e46 183f 8d10 1a3f cad7 1b3f  .y.?NF.?...?...?
0000130: fe9b 1d3f 1f5d 1f3f 241b 213f 06d6 223f  ...?.].?$.!?.."?
0000140: bb8d 243f 3a42 263f 7cf3 273f 78a1 293f  ..$?:B&?|.'?x.)?
0000150: 254c 2b3f 7bf3 2c3f 7297 2e3f 0138 303f  %L+?{.,?r..?.80?
0000160: 22d5 313f ca6e 333f                      ".1?.n3?

Quel est le sinus des 90 premiers degrés dans les flotteurs binaires de 4 octets


Et comment saisir des valeurs binaires de cette manière?
cprcrack

Je l' utilise xxd -r(ou od) pour filtrer le document
sehe

Pourriez-vous l'expliquer avec un exemple? Je n'ai pas réussi à le faire.
cprcrack

1
voir la réponse modifiée. Le point est de ne pas inclure des données binaires brutes dans votre script, mais au lieu filtrer à travers un programme comme xxd
sehe

A quoi ça sert: "/ mon / bash / script <<< 'Cette chaîne sera envoyée à stdin.'" Quand vous pouvez dire directement: "/ mon / bash / script 'Cette chaîne sera envoyée à stdin. '"?
Baiyan Huang

2

Vous pouvez également utiliser readcomme ça

echo "enter your name"
read name
echo $name

2

Solution

Vous voulez (1) créer une sortie stdout dans un processus (comme echo '…') et (2) rediriger cette sortie vers l'entrée stdin d'un autre processus mais (3) sans utiliser le mécanisme de canal bash. Voici une solution qui correspond aux trois conditions:

/my/bash/script < <(echo 'This string will be sent to stdin.')

La <redirection d'entrée est normale pour stdin. La <(…)substitution de processus est bash. En gros, il crée un /dev/fd/…fichier avec la sortie de la commande de substitution et passe ce nom de fichier à la place de <(…), ce qui entraîne ici par exemple script < /dev/fd/123. Pour plus de détails, consultez cette réponse

Comparaison avec d'autres solutions

  • Un heredoc d'une ligne envoyé à stdin script <<< 'string'permet uniquement d'envoyer des chaînes statiques, pas la sortie d'autres commandes.

  • La substitution de processus seule, comme dans diff <(ls /bin) <(ls /usr/bin), n'envoie rien à stdin. Au lieu de cela, la sortie du processus est transmise en tant que contenu des fichiers créés en arrière-plan, équivalent à par exemple diff /dev/fd/10 /dev/fd/11. Dans cette commande, diffn'obtient aucune entrée de stdin.

Cas d'utilisation

J'aime ça, contrairement au mécanisme de pipe, le < <(…)mécanisme permet de mettre la commande en premier et toutes les entrées après, comme c'est la norme pour l'entrée à partir des options de ligne de commande.

Cependant, au-delà de l'esthétique de la ligne de commande, il existe certains cas où un mécanisme de tuyau ne peut pas être utilisé. Par exemple, lorsqu'une certaine commande doit être fournie comme argument d'une autre commande, comme dans cet exemple avecsshpass .


Alternative intéressante. Cela se produit-il pour être conforme à POSIX contrairement à <<<?
Tous les travailleurs sont essentiels

0
cat | /my/bash/script

Permet de taper plusieurs lignes dans un programme, sans que cette entrée ne soit enregistrée dans l'historique, ni visible dans ps. Appuyez simplement sur Ctrl + C lorsque vous avez terminé de taper pour terminer cat.


-1

les alias peuvent et ne peuvent pas traiter stdin canalisé ...

Ici, nous créons 3 lignes de sortie

$ echo -e "line 1\nline 2\nline 3"
line 1
line 2
line 3

Nous dirigeons ensuite la sortie vers stdin de la commande sed pour les mettre tous sur une seule ligne

$ echo -e "line 1\nline 2\nline 3" |  sed -e ":a;N;\$!ba ;s?\n? ?g"
line 1 line 2 line 3

Si nous définissons un alias de la même commande sed

$ alias oline='sed -e ":a;N;\$!ba ;s?\n? ?g"'

Nous pouvons diriger la sortie vers le stdin de l'alias et il se comporte exactement de la même manière

$ echo -e "line 1\nline 2\nline 3" |  oline
line 1 line 2 line 3

Le problème se pose lorsque nous essayons de définir l'alias comme une fonction

$ alias oline='function _oline(){ sed -e ":a;N;\$!ba ;s?\n? ?g";}_oline'

Définir l'alias comme une fonction brise le tuyau

$ echo -e "line 1\nline 2\nline 3" |  oline
>

Premièrement, cela ne répond pas à la question - peut-être avez-vous répondu à la mauvaise question? Deuxièmement, pourquoi définiriez-vous une fonction à l'intérieur d'un alias? Tu devrais juste faire function oline() { sed -e ":a;N;\$!ba ;s?\n? ?g"; }. Troisièmement, ce sed serait beaucoup plus compréhensible avec awk:awk -F '\n' 'ORS=" " { print } END { printf "\n"}'
Leonardo Dagnino
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.