Enviar cadena a stdin

158

¿Hay alguna manera de hacer esto efectivamente en bash?

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

Soy consciente de que podría canalizar la salida del eco como este:

echo 'This string will be piped to stdin.' | /my/bash/script
Todos los trabajadores son esenciales
fuente
1
¿Qué quiere decir con eficacia , por qué la tubería no es una forma de hacer esto?
Andy
Ambos comandos que enumeró deberían hacer exactamente lo mismo. ¿Qué problema estás teniendo?
Flimzy
55
@Flimzy: afaik, el primero no funcionará como se esperaba, intentará abrir un archivo llamadoecho
Andy
Correcto. Entonces, ¿qué hay de malo con la segunda forma?
Flimzy
2
@Flimzy: además, el >formulario de redirección abrirá un descriptor de archivo como fd 0(stdin), mientras que |opens inicia un proceso hijo y adjunta su stdout (fd 1) al stdin del otro proceso. Este hecho puede tener consecuencias no triviales (piensan acerca de compartir las variables de entorno?)
sehe

Respuestas:

262

Puedes usar una línea heredoc

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

lo anterior es lo mismo que

cat <<EOF
This is coming from the stdin
EOF

o puede redirigir la salida de un comando, como

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

o puedes leer como

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

o simplemente

echo something | read param
jm666
fuente
¿Y cómo ingresar valores binarios de esta manera? Sin necesidad de utilizar el tubo (sé que se puede hacer con el tubo de la siguiente manera: echo -e "\x01\x02..." | ./script)
cprcrack
Me gusta escribirlo de la otra manera: <<< "Esto viene de stdin" perl ..., de esta manera se ve como el lado izquierdo de la tubería.
Pirolítico
@Pirolístico sí! Especialmente útil cuando se domina, por ejemplo, un perl oneliner desde una línea de comando: edición fácil de los argumentos de perl sin la necesidad de muchos movimientos hacia atrás con un cursor. :)
jm666
@ jm666 lo triste es que aprendí ayer si usas un alias bash, solo usas el formulario command_alias <<< "stdin string", de lo contrario, dirá comando no encontrado
Pyrolistical
@ jm666 ¿Hay algún lugar sobre el que pueda aprender más <<<? Me da vergüenza admitir que nunca lo había visto antes, y estoy totalmente desconcertado por ello. Intenté buscarlo en Google, pero mis resultados no han estado relacionados.
wpcarro
66

Estabas cerca

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

Para entrada multilínea, los documentos aquí son adecuados:

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

Editar a los comentarios:

Para lograr una entrada binaria, diga

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 se sustituye catpor /my/bash/script(o, de hecho cae la última pipa), esta impresiones:

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

O, si querías algo un poco más 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?

¿Cuáles son los senos de los primeros 90 grados en flotadores binarios de 4 bytes?

sehe
fuente
¿Y cómo ingresar valores binarios de esta manera?
cprcrack
Que haría uso xxd -r(o od) para filtrar el documento AQUÍ
sehe
¿Podrías explicarlo con un ejemplo? No pude hacerlo.
cprcrack
1
ver la respuesta editada El punto es no incluir datos binarios sin procesar en su secuencia de comandos, sino filtrarlos a través de un programa como xxd
sehe
¿Cuál es el punto de hacer: "/ my / bash / script <<< 'Esta cadena se enviará a stdin.'" Cuando puede decir directamente: "/ my / bash / script 'Esta cadena se enviará a stdin. '"?
Baiyan Huang
2

También puedes usar readasí

echo "enter your name"
read name
echo $name
Rahul
fuente
2

Solución

Desea (1) crear salida echo '…'estándar en un proceso (como ) y (2) redirigir esa salida a la entrada estándar de otro proceso pero (3) sin el uso del mecanismo de tubería bash. Aquí hay una solución que coincide con las tres condiciones:

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

La <redirección de entrada es normal para stdin. La <(…)sustitución del proceso es bash. Aproximadamente crea un /dev/fd/…archivo con la salida del comando de sustitución y pasa ese nombre de archivo en lugar del <(…), lo que resulta aquí, por ejemplo, en script < /dev/fd/123. Para más detalles, vea esta respuesta

Comparación con otras soluciones.

  • Un heredoc de una línea enviado a stdin script <<< 'string'solo permite enviar cadenas estáticas, no la salida de otros comandos.

  • La sustitución de procesos sola, como en diff <(ls /bin) <(ls /usr/bin), no envía nada a stdin. En cambio, la salida del proceso se pasa como el contenido de los archivos creados en segundo plano, equivalente a, por ejemplo diff /dev/fd/10 /dev/fd/11. En ese comando, diffno recibe ninguna entrada de stdin.

Casos de uso

Me gusta que, a diferencia del mecanismo de tubería, el < <(…)mecanismo permite poner el comando primero y toda la entrada después, como es el estándar para la entrada desde las opciones de la línea de comando.

Sin embargo, más allá de la estética de la línea de comandos, hay algunos casos en los que no se puede utilizar un mecanismo de tubería. Por ejemplo, cuando se debe proporcionar un determinado comando como argumento para otro comando, como en este ejemplo consshpass .

Tanius
fuente
Alternativa interesante ¿Esto sucede a diferencia de POSIX <<<?
Todos los trabajadores son esenciales
0
cat | /my/bash/script

Le permite a uno escribir múltiples líneas en un programa, sin que esa entrada se guarde en el historial, ni visible en ps. Simplemente presione Ctrl + C cuando termine de escribir para finalizar cat.

Walf
fuente
-1

los alias pueden y no pueden procesar stdin canalizado ...

Aquí creamos 3 líneas de salida.

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

Luego canalizamos la salida a stdin del comando sed para ponerlos a todos en una línea

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

Si definimos un alias del mismo comando sed

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

Podemos canalizar la salida al stdin del alias y se comporta exactamente igual

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

El problema surge cuando intentamos definir el alias como una función

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

Definir el alias como una función rompe la tubería

$ echo -e "line 1\nline 2\nline 3" |  oline
>
KenB
fuente
En primer lugar, esto no responde la pregunta, ¿tal vez usted respondió la pregunta incorrecta? En segundo lugar, ¿por qué definirías una función dentro de un alias? Solo deberías hacerlo function oline() { sed -e ":a;N;\$!ba ;s?\n? ?g"; }. En tercer lugar, esto sería mucho más comprensible con awk:awk -F '\n' 'ORS=" " { print } END { printf "\n"}'
Leonardo Dagnino