Automatizar la entrada de texto desde un script bash sin usar EOF

10

Estoy ejecutando Ubuntu Linux. Supongamos que hay un programa llamado myprogram. Este programa solicita al usuario que ingrese; específicamente, el usuario debe escribir un número entero cuando se le solicite y presionar Enter. Me gustaría automatizar este proceso usando un script bash. En particular, me gustaría ejecutar myprogram, digamos, 100 veces (usando un contador ique va de 1a 100). En cada ejecución de myprogram, me gustaría ingresar el valor actual de icuando se me solicite.

(Por cierto, myprogramtoma opciones / modificadores -options, todos los cuales serán constantes y, por lo tanto, se especificarán dentro del script bash).

Un esqueleto incompleto de este script bash podría ser:

#!/bin/bash
for i in {1..100}
do
   myprogram -options
done

Ahora me gustaría modificar el código anterior para que ise ingrese el valor actual de cuando el programa lo solicite. ¿Cuál es la mejor manera de hacer esto?

El sitio web del software que estoy usando sugiere usarlo <<EOFal final de la myprogram -optionslínea. Creo que esto le dice a bash que mire el "final del archivo" para la entrada a usar. Pero, ¿qué pasa si no quiero colocar la entrada al final del archivo? ¿Qué pasa si me gustaría ponerlo inmediatamente después de <<o <?

La razón es que las cosas se pondrán más complicadas. Por ejemplo, puedo introducir un contador entero jque cambia de una manera no lineal, no secuencial. Entonces me gustaría alimentar el valor actual de ja myprogramen cada iteración, pero el valor de jpuede cambiar entre la llamada myprogram -optionsy el final del archivo EOF.

¿Tienes alguna sugerencia?

Andrés
fuente
Consulte este blog - Ejecución de programas interactivos
Suresh

Respuestas:

14

Para casi todos los programas, tanto echo $i | myprogram -optionsy myprogram -options <<<$idebería funcionar, alimentando el programa $ia través de la entrada estándar.

<fooutilizará el contenido del archivo denominado foostdin.

<<fooutilizará el texto entre eso y una línea que consiste únicamente foocomo entrada estándar. Este es un documento aquí (heredoc), como dijo Gilles; EOFen realidad no significa el final del archivo, es solo un delineador heredoc común (en este ejemplo usamos "foo").

<<<fooutilizará la cadena "foo" como entrada estándar. También puede especificar una variable $foo, y el shell usará su contenido como stdin, como lo mostré anteriormente. Esto se llama herejía , ya que usa una cadena corta en contraste con un bloque completo, como en un heredoc. Las herejías funcionan en bash, pero no en /bin/sh.

Kevin
fuente
9

La sintaxis recomendada por este sitio web se denomina documento aquí . La entrada al programa de archivo comienza inmediatamente debajo de la línea que contiene <<EOF, y no termina al final del script, sino por una línea que contiene exactamente el texto EOF(tenga cuidado de no tener espacios en blanco adicionales). Por cierto, puede usar cualquier marcador final que no contenga ningún carácter especial de shell: EOFno es una palabra clave, es simplemente tradicional.

#!/bin/bash
for i in {1..100}
do
   myprogram -options <<EOF
$i
EOF
   for j in {1..42}; do
     myprogram2 <<EOF
$i
$j
EOF
   done
done
Gilles 'SO- deja de ser malvado'
fuente
en otras palabras, EOF en este contexto significa un marcador de fin de archivo , no el final real del archivo de script. el texto "EOF" es cualquier texto arbitrario, lo que sea que use inmediatamente después de los caracteres << indicará el final del documento aquí y ahora. Por lo general, uso EOF porque se destaca y es muy poco probable que esté dentro del documento siguiente si, por ejemplo, estoy generando programáticamente el script de shell (lo cual hago con bastante frecuencia).
cas
ese EOF en negrita debería ser <underscore><underscore>EOF<underscore> <underscore>
cas
Utilizando documentos como este, a menudo he cambiado el marcador final a algo mucho más significativo (y menos probable que coincida "al azar"), como END_OF_WHATEVER_FUNCTION. A veces, tratar de "ahorrar" espacio / tamaño es en realidad una pérdida de esfuerzo porque causa ambigüedad sobre lo que realmente está sucediendo.
killermist
¿Cómo puedes sleepleer entre los comandos del script?
boltup_im_coding
@ inesperado62 No entiendo lo que estás preguntando. Probablemente debería hacer una nueva pregunta en este sitio. Asegúrese de dar suficiente contexto.
Gilles 'SO- deja de ser malvado'
3

aquí los documentos mencionados por Kevin y Gilles anteriormente, o la tubería simple funcionará en muchos casos.

Para situaciones más complicadas, es posible que desee examinar Expect o similar (por ejemplo, el módulo Expect :: Simple CPAN es una implementación perl muy fácil de usar). personalmente, prefiero el módulo perl (se espera que sea tcl) pero hay implementaciones para muchos lenguajes de script comunes. Incluso es posible escribir una implementación muy primitiva de la idea en sh o bash usando while y read.

La idea general de Expect y herramientas similares es esperar una cadena o patrón específico en la salida de un programa y luego alimentarlo con la entrada que desee.

Un ejemplo de uso común es automatizar el inicio de sesión, "esperando" (es decir, esperando) la cadena "ogin:", envíe el nombre de inicio de sesión, luego espere la cadena "palabra:" y envíe la contraseña.

Una opción final, si tiene la fuente de myprogram, es simplemente modificarla para tomar la entrada que desea dar como una opción de línea de comando. Esto podría ser un poco más de trabajo por adelantado, pero será mucho menos irritante que jugar con Expect o canalizar datos en un programa que no fue diseñado para usarse de esa manera.

... y no olvides enviar tu parche a myprogram nuevamente :) Incluso si no les gusta la forma en que lo has codificado, tal vez les guste la idea lo suficiente como para agregar la función ellos mismos. Los desarrolladores ascendentes tienden a apreciar a las personas que se salen de su trasero y contribuyen en lugar de exigir o quejarse.

cas
fuente