Estoy ejecutando Ubuntu Linux. Supongamos que hay un programa llamado myprogram
. Este programa solicita al usuario información; 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 i
que va de 1
a 100
). En cada ejecución de myprogram
, me gustaría ingresar el valor actual de i
cuando se me solicite.
(Por cierto, myprogram
toma opciones/interruptores -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 i
se 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 sugiereusando <<EOF
al final de la myprogram -options
línea. Creo que esto le dice a bash que busque en el "final del archivo" la entrada que va a utilizar. Pero ¿qué pasa si no quiero colocar la entrada en elfindel archivo? ¿Qué pasa si quisiera ponerlo inmediatamente después de <<
o <
?
La razón es que las cosas se complicarán más. Por ejemplo, puedo introducir un contador de números enteros j
que cambie de alguna manera no lineal ni secuencial. Luego me gustaría introducir el valor actual de j
to myprogram
en cada iteración, pero el valor de j
puede cambiar entre la llamada a myprogram -options
y el final del archivo EOF
.
¿Tienes alguna sugerencia?
Respuesta1
Para casi todos los programas, ambos echo $i | myprogram -options
y myprogram -options <<<$i
deberían funcionar, alimentando el programa $i
a través de la entrada estándar.
<foo
utilizará el contenido del archivo denominado foo
stdin.
<<foo
utilizará el texto entre eso y una línea que consta únicamente de foo
como entrada estándar. Esto es unaquí documento(heredoc), como dijo Gilles; EOF
en realidad no significa el final del archivo, es solo un delineador heredoc común (en este ejemplo usamos "foo" en su lugar).
<<<foo
utilizará la cadena "foo" como entrada estándar. También puede especificar una variable $foo
y el shell usará su contenido como entrada estándar, como mostré arriba. Esto se llama unheredero, ya que utiliza una cadena corta en contraste con un bloque completo, como en un heredoc. Las cadenas Herestrings funcionan en bash, pero no en /bin/sh
.
Respuesta2
La sintaxis recomendada por este sitio web se denominaaquí documento. La entrada al archivo del programa comienza inmediatamente debajo de la línea que contiene <<EOF
y no termina al final del script, sino en una línea que contiene exactamente el texto EOF
(tenga cuidado de no tener espacios en blanco adicionales). Por cierto, puedes usar cualquier marcador final que no contenga ningún carácter especial del shell: EOF
no es una palabra clave, es meramente 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
Respuesta3
Aquí los documentos mencionados anteriormente por Kevin y Gilles, o una simple tubería funcionarán en muchos casos.
Para situaciones más complicadas, es posible que desee consultar Expect o algo similar (por ejemplo, el módulo Expect::Simple CPAN es una implementación de Perl muy fácil de usar). Personalmente, prefiero el módulo Perl (Expect en sí es tcl), pero existen implementaciones para muchos lenguajes de scripting comunes. Incluso es posible escribir unmuyImplementación 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 última opción, si tiene la fuente de myprogram, es simplemente modificarla para tomar la entrada que desea darle como opción de línea de comando. Esto podría requerir un poco más de trabajo por adelantado, pero será mucho menos irritante que jugar con Expect o canalizar datos a 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, es posible que les guste la idea lo suficiente como para agregar la función ellos mismos. Los desarrolladores upstream tienden a apreciar a las personas que se esfuerzan y contribuyen en lugar de exigir o quejarse.