Pase texto al programa esperando un archivo

30

Relacionado con una pregunta que hice en Stack Overflow: ¿ Pasar varias líneas de código a wsadmin.sh?.

Tengo, como una cadena, algunas líneas de entrada que necesito alimentar en un comando. El comando, sin embargo, solo acepta un archivo lleno de entrada.

¿Hay alguna forma de que pueda almacenar las líneas en un archivo o tubería temporal que nunca se escribe en el disco y luego introducirlo directamente en el programa?

¿Cómo hago para adquirir la tubería, alimentar la entrada, pasar esa tubería al comando y luego deshacerme de la tubería?

ArtOfWarfare
fuente
2
¿Puedes agregar un ejemplo del comando que estás usando y cómo se supone que debe invocarse?
Avance
2
¿Eso significa que el programa no acepta stdin?
Léo Lam
Estoy de acuerdo con los dos comentaristas anteriores. Es imposible sugerir algo que pueda funcionar sin conocer las especificaciones del programa.
Larssend

Respuestas:

27

Otra solución es usar la sustitución de procesos en Bash. Si su sistema ha nombrado tuberías, puede usar esta función.

Se usa así:

program_expecting_a_file <(list)

donde listhay una secuencia de comandos de shell (en realidad tuberías; los detalles completos están aquí ). listse ejecutará y su salida se conectará a la tubería. El nombre de la tubería se pasa a su programa.

NOTA: no se permiten espacios entre <y (.

(La otra sustitución >(list)también funciona como es de esperar).

En su caso específico, podría usar

program_expecting_a_file <(echo "$your_strings")

aunque puede encontrar la solución de @ meuh para ser más elegante.

Actualización: En la Guía avanzada de secuencias de comandos de Bash encontrará muchos ejemplos de uso .

Eduardo
fuente
Los otros dos no funcionaron incluso en los casos más triviales. El tuyo pasa las pruebas que le he hecho hasta ahora. He votado por el tuyo por ahora. Volveré y marcaré esto como aceptado si hace todo lo que necesito.
ArtOfWarfare
El tuyo funciona perfectamente. Si lo desea, puede agregarlo a la pregunta relacionada en StackOverflow y también puedo aceptarlo allí. stackoverflow.com/questions/31374202/…
ArtOfWarfare
Hola @ArtOfWarfare, me alegro de poder ayudarte. Ya hay un comentario allí con la misma solución propuesta, por lo que no sería correcto para mí publicar una respuesta allí.
Edward
Publicó su solución antes que él. De todos modos, le he pedido que cambie su comentario a una respuesta para poder aceptarlo. Si ninguno de ustedes publica las respuestas dentro de las 24 horas posteriores a esa pregunta, solo publicaré la respuesta para que pueda aceptarla (no me gusta dejar que mis preguntas aparezcan sin respuesta una vez que he encontrado cuál es la respuesta. Es solo malos modales para futuros lectores / posibles respondedores de la pregunta.)
ArtOfWarfare
Hola @ArtOfWarfare, estoy absolutamente de acuerdo con lo que propones.
Edward
15

Puedes usar un bash here-doc . Por ejemplo,

$ cat -n <<<'a
> b'
 1  a
 2  b

Si tiene algo en una variable bash, también puede interpolarlo: por ejemplo <<<"path is $PATH".


Si su comando insiste en un nombre de archivo, puede darle /dev/stdin. P.ej:

$ sed -f /dev/stdin <<<'s/a/b/'

produce la salida de: s/b/b/.

meuh
fuente
No queda claro a partir de la pregunta si el comando acepta entrada stdin, y si no, esto no va a funcionar. Espero que el OP aclare.
David Z
1
:( - Esto parecía muy prometedor, pero cuando lo intenté, recibí el mensaje de error"-f" option must be followed by a file name.
ArtOfWarfare
Un documento aquí es para stdin. Si su comando necesita absolutamente -fy un nombre de archivo, proporcione el nombre de archivo /dev/stdin. Mira mi edición.
meuh
¡Creo que después de las ediciones es absolutamente una opción viable!
Edward
1
+1 por la /dev/stdinsugerencia. El programa al que intento llamar solo acepta un nombre de archivo, así que lo he combinado /dev/stdincon un heredoc.
Huw Walters
7

Dependiendo de lo que esté en el script, puede usar el nombre de archivo especial - (menos) que significa stdin

$ mycmd -
Line 1
Line 2
^D

Otro método que puede funcionar para usted es abrir el archivo /dev/fd/0que nuevamente significa stdin .

Una tercera opción puede ser crear un FIFO (Primero en entrar, primero en salir). Es como un archivo, pero tiene dos extremos: escribe en un extremo y lee desde el otro.

-- Process 1 --                  -- Process 2 --
$ mkfifo foo
$ cat foo
<waits>                          $ echo hello > foo
hello                            $
$ rm foo
Majenko
fuente
3
Vale la pena señalar que el programa tiene que ser escrito para interpretarlo de -esta manera: no es una característica del shell o del sistema operativo. Aunque, por lo que sé, la mayoría de las utilidades estándar de Linux siguen esta convención.
David Z
1
No Esto no funciona para el programa. Hay un modo interactivo, pero quiero pasar los comandos para ejecutar a este programa desde otro programa, y ​​no quiero entrar en el agujero del conejo que es expect.
ArtOfWarfare
@ArtOfWarfare Acabo de agregar una tercera opción que puede funcionar.
Majenko
¡Buena respuesta! Las opciones segunda y tercera son básicamente como la <()solución, pero más explícitas, ¡lo cual puede ser muy útil!
Edward
4

Hay otra opción similar a la mycmd -solución, pero incluso para programas que no manejan -específicamente:

$ mycmd /dev/stdin
Line 1
Line 2
^D

/dev/stdin parece estar relacionado con el sistema operativo y funciona para mí en Debian GNU / Linux, pero no estoy seguro de dónde funcionará también.

Axel Beckert
fuente
1
Parece que podría funcionar, pero ¿qué es ^D?
ArtOfWarfare
^Des una notación común para presionar Ctrl-D. ^ D tiene la semántica de "fin de flujo de entrada" aquí. Probablemente se ve con más frecuencia en ^Co ^Zqué significa presionar Ctrl-C respectivamente para presionar Ctrl-Z.
Axel Beckert
1
Eso parece funcionar, pero ¿cómo pondré cosas programáticamente /dev/stdiny luego las cerraré?
ArtOfWarfare
1
Simplemente conecte algo a ese comando y debería funcionar, es decir cat content | mycmd /dev/stdin. Solo imagine comandos diferentes que cataquí.
Axel Beckert