Comando expect de Linux con Ejemplos Prácticos

LinuxBeginner
Practicar Ahora

Introducción

En este laboratorio, aprenderá a usar el comando expect de Linux para automatizar aplicaciones interactivas de línea de comandos. El comando expect es una poderosa herramienta de automatización que permite a los scripts interactuar con programas que requieren entrada del usuario, como SSH, FTP y otros programas interactivos.

Al final de este laboratorio, podrá:

  • Comprender el propósito y la sintaxis básica del comando expect
  • Crear scripts para automatizar inicios de sesión SSH
  • Manejar varios prompts y respuestas en sus scripts expect

El comando expect puede reducir significativamente la intervención manual para tareas repetitivas, haciendo que la administración del sistema y las tareas de rutina sean más eficientes. Comenzará instalando y explorando la sintaxis básica de expect, luego progresará a la creación de scripts para automatizar los inicios de sesión SSH y manejar varios prompts interactivos.

Hoja de trucos de comandos de Linux

Comprender el comando expect y su sintaxis básica

El comando expect en Linux le permite automatizar programas interactivos de línea de comandos que normalmente requieren entrada del usuario. Esto es particularmente útil para tareas como inicios de sesión automatizados, transferencias de archivos o cualquier situación en la que un programa solicite entrada.

Instalación de expect

Primero, verifiquemos que el paquete expect esté instalado en nuestro sistema. Abra su terminal y ejecute:

which expect

Si expect ya está instalado, verá su ruta (como /usr/bin/expect). Si no, necesitará instalarlo:

sudo apt-get update
sudo apt-get install -y expect

Comprender la sintaxis básica de expect

El comando expect utiliza un lenguaje de scripting basado en Tcl (Tool Command Language). La estructura básica de un script expect incluye los siguientes comandos:

  1. spawn: Inicia un proceso con el que interactuar
  2. expect: Espera una salida específica del proceso generado
  3. send: Envía entrada al proceso generado
  4. set timeout: Establece cuánto tiempo esperar la salida esperada

Creemos un script expect simple para demostrar estos conceptos. Abra un editor de texto y cree un archivo llamado hello.exp en su directorio de proyecto:

cd ~/project
nano hello.exp

Escriba el siguiente contenido en el archivo:

#!/usr/bin/expect -f

## Set a timeout of 10 seconds
set timeout 10

## Spawn the bash process
spawn bash

## Wait for the bash prompt
expect "$ "

## Send a command to the bash process
send "echo Hello from expect\r"

## Wait for the bash prompt again
expect "$ "

## Exit the bash session
send "exit\r"

## Wait for the process to complete
expect eof

Guarde el archivo presionando Ctrl+O, luego Enter, y salga de nano con Ctrl+X.

Haga que el script sea ejecutable:

chmod +x ~/project/hello.exp

Ahora ejecute el script:

~/project/hello.exp

Debería ver una salida similar a esta:

spawn bash
$ echo Hello from expect
Hello from expect
$ exit
exit

Comprender cada línea del script

Permítame explicar qué hace cada línea del script:

  • #!/usr/bin/expect -f: Esta es una línea shebang que le dice al sistema que use el intérprete expect para ejecutar este script.
  • set timeout 10: Esto establece un tiempo de espera de 10 segundos para cualquier comando expect que siga.
  • spawn bash: Esto inicia un nuevo proceso de shell bash con el que expect interactuará.
  • expect "$ ": Esto espera a que aparezca el prompt de bash.
  • send "echo Hello from expect\r": Esto envía el comando al shell bash. Observe el \r al final, que simula presionar Enter.
  • expect "$ ": Esto espera el prompt de bash nuevamente, después de que se haya ejecutado el comando.
  • send "exit\r": Esto envía el comando exit para cerrar el shell bash.
  • expect eof: Esto espera a que el proceso generado termine.

Este simple ejemplo demuestra la funcionalidad principal de expect. En los siguientes pasos, usaremos estos conceptos para crear scripts más prácticos.

Creación de un script de inicio de sesión SSH simulado con expect

En este paso, crearemos un script expect que simula un proceso de inicio de sesión SSH. Dado que no podemos realizar un inicio de sesión SSH real en este entorno, crearemos un script simulado que demuestre los principios.

Comprender el flujo de autenticación SSH

Al conectarse a un servidor remoto a través de SSH, la interacción típica implica:

  1. Iniciar la conexión con ssh username@hostname
  2. Aceptar la clave del host (si se conecta por primera vez)
  3. Ingresar su contraseña cuando se le solicite
  4. Obtener acceso al shell remoto

Creemos un entorno SSH simulado para demostrar cómo expect puede automatizar este proceso.

Creación de un script de servidor SSH simulado

Primero, creemos un script que simule un servidor SSH solicitando una contraseña:

cd ~/project
nano mock_ssh_server.sh

Ingrese el siguiente contenido:

#!/bin/bash

echo "The authenticity of host 'mockserver' can't be established."
echo "RSA key fingerprint is SHA256:abcdefghijklmnopqrstuvwxyz123456."
echo "Are you sure you want to continue connecting (yes/no)? "
read answer

if [ "$answer" != "yes" ]; then
  echo "Host key verification failed."
  exit 1
fi

echo "Warning: Permanently added 'mockserver' (RSA) to the list of known hosts."
echo "Password: "
read -s password

if [ "$password" == "mockpassword" ]; then
  echo "Last login: Wed Nov 1 12:00:00 2023 from 192.168.1.100"
  echo "Welcome to Mock SSH Server"
  echo "mockuser@mockserver:~$ "

  while true; do
    read -p "" command
    if [ "$command" == "exit" ]; then
      echo "Connection to mockserver closed."
      exit 0
    else
      echo "Executing: $command"
      echo "mockuser@mockserver:~$ "
    fi
  done
else
  echo "Permission denied, please try again."
  exit 1
fi

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/mock_ssh_server.sh

Este script simula:

  • El prompt de verificación del host SSH
  • El prompt de contraseña
  • Un shell simple que responde a los comandos

Creación de un script expect para automatizar el inicio de sesión

Ahora, creemos un script expect que automatice la interacción con nuestro servidor SSH simulado:

cd ~/project
nano ssh_login.exp

Ingrese el siguiente contenido:

#!/usr/bin/expect -f

## Set variables
set timeout 10
set password "mockpassword"

## Start the mock SSH server
spawn ./mock_ssh_server.sh

## Handle the host verification prompt
expect "Are you sure you want to continue connecting (yes/no)? "
send "yes\r"

## Handle the password prompt
expect "Password: "
send "$password\r"

## Wait for the shell prompt
expect "mockuser@mockserver:~$ "

## Execute a command
send "ls -la\r"
expect "mockuser@mockserver:~$ "

## Exit the session
send "exit\r"

## Wait for the process to complete
expect eof

puts "\nSSH login automation completed successfully!"

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/ssh_login.exp

Ejecución del script de inicio de sesión automatizado

Ahora, ejecutemos nuestro script expect para automatizar la interacción con el servidor SSH simulado:

cd ~/project
./ssh_login.exp

Debería ver una salida similar a esta:

spawn ./mock_ssh_server.sh
The authenticity of host 'mockserver' can't be established.
RSA key fingerprint is SHA256:abcdefghijklmnopqrstuvwxyz123456.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'mockserver' (RSA) to the list of known hosts.
Password:
Last login: Wed Nov 1 12:00:00 2023 from 192.168.1.100
Welcome to Mock SSH Server
mockuser@mockserver:~$ ls -la
Executing: ls -la
mockuser@mockserver:~$ exit
Connection to mockserver closed.

SSH login automation completed successfully!

Explicación del script

Permítame explicar qué hace cada parte de nuestro script expect:

  1. set timeout 10: Establece un tiempo de espera global de 10 segundos para todos los comandos expect.
  2. set password "mockpassword": Almacena la contraseña en una variable.
  3. spawn ./mock_ssh_server.sh: Inicia nuestro script de servidor SSH simulado.
  4. expect "Are you sure you want to continue connecting (yes/no)? ": Espera el prompt de verificación del host.
  5. send "yes\r": Envía "yes" para aceptar la clave del host.
  6. expect "Password: ": Espera el prompt de contraseña.
  7. send "$password\r": Envía la contraseña.
  8. expect "mockuser@mockserver:~$ ": Espera el prompt del shell.
  9. send "ls -la\r": Envía un comando para listar archivos.
  10. expect "mockuser@mockserver:~$ ": Espera el prompt del shell nuevamente.
  11. send "exit\r": Envía el comando exit para cerrar la sesión.
  12. expect eof: Espera a que el proceso termine.
  13. puts "\nSSH login automation completed successfully!": Imprime un mensaje de éxito.

Este ejemplo demuestra cómo expect se puede usar para automatizar todo el proceso de inicio de sesión SSH, desde aceptar la clave del host hasta ejecutar comandos en el servidor remoto y salir de forma segura.

Manejo de múltiples prompts y respuestas con expect

En escenarios del mundo real, los programas interactivos a menudo presentan múltiples prompts y pueden requerir diferentes respuestas basadas en diferentes condiciones. En este paso, aprenderemos a manejar múltiples prompts y respuestas condicionales en scripts expect.

Comprender los bloques condicionales expect

El comando expect se puede usar con una estructura de bloque de patrón-acción para manejar diferentes prompts posibles:

expect {
    "pattern1" { actions for pattern1 }
    "pattern2" { actions for pattern2 }
    timeout { actions for timeout }
    eof { actions for end of file }
}

Esta estructura permite que su script responda de manera diferente dependiendo de la salida que reciba.

Creación de un script de manejo de múltiples prompts

Creemos un script que simule un programa con múltiples prompts:

cd ~/project
nano multi_prompt.sh

Ingrese el siguiente contenido:

#!/bin/bash

echo "Please select an option:"
echo "1. Show date and time"
echo "2. List files"
echo "3. Show system info"
echo "4. Exit"
echo -n "Enter your choice (1-4): "
read choice

case $choice in
  1)
    echo "Current date and time:"
    date
    ;;
  2)
    echo "File listing:"
    ls -la
    ;;
  3)
    echo "System information:"
    uname -a
    ;;
  4)
    echo "Exiting program..."
    exit 0
    ;;
  *)
    echo "Invalid option. Please enter a number between 1 and 4."
    exit 1
    ;;
esac

echo "Do you want to continue? (yes/no): "
read answer

if [ "$answer" == "yes" ]; then
  echo "Continuing..."
  echo "Operation completed successfully."
else
  echo "Exiting program..."
fi

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/multi_prompt.sh

Ahora, creemos un script expect para interactuar con este programa y manejar todos los prompts posibles:

cd ~/project
nano handle_prompts.exp

Ingrese el siguiente contenido:

#!/usr/bin/expect -f

## Set a timeout
set timeout 10

## Start the multi-prompt program
spawn ./multi_prompt.sh

## Wait for the choice prompt
expect "Enter your choice (1-4): "

## Generate a random choice (1-3)
set choice [expr {int(rand() * 3) + 1}]
send "$choice\r"

## Process the result based on the choice
switch $choice {
    1 {
        expect "Current date and time:"
        expect "Do you want to continue? (yes/no): "
    }
    2 {
        expect "File listing:"
        expect "Do you want to continue? (yes/no): "
    }
    3 {
        expect "System information:"
        expect "Do you want to continue? (yes/no): "
    }
}

## Handle the continue prompt
expect {
    "Do you want to continue? (yes/no): " {
        ## 70% chance to say yes, 30% chance to say no
        if {rand() < 0.7} {
            send "yes\r"
            expect "Operation completed successfully."
        } else {
            send "no\r"
            expect "Exiting program..."
        }
    }
    timeout {
        puts "Timeout waiting for continue prompt"
        exit 1
    }
}

## Wait for the program to complete
expect eof

puts "\nMulti-prompt handling completed successfully!"

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/handle_prompts.exp

Ejecución del script de manejo de múltiples prompts

Ahora, ejecutemos nuestro script expect para interactuar con el programa de múltiples prompts:

cd ~/project
./handle_prompts.exp

Cada vez que ejecute este script, seleccionará aleatoriamente una de las opciones y decidirá aleatoriamente si continuar o salir. Aquí hay un ejemplo de salida:

spawn ./multi_prompt.sh
Please select an option:
1. Show date and time
2. List files
3. Show system info
4. Exit
Enter your choice (1-4): 2
File listing:
total 20
drwxr-xr-x 2 labex labex 4096 Nov  1 10:00 .
drwxr-xr-x 4 labex labex 4096 Nov  1 10:00 ..
-rwxr-xr-x 1 labex labex  345 Nov  1 10:00 handle_prompts.exp
-rwxr-xr-x 1 labex labex  578 Nov  1 10:00 multi_prompt.sh
-rwxr-xr-x 1 labex labex  221 Nov  1 10:00 ssh_login.exp
Do you want to continue? (yes/no): yes
Continuing...
Operation completed successfully.

Multi-prompt handling completed successfully!

Creación de un script expect más avanzado

Ahora, creemos un script más avanzado que pueda manejar prompts y errores inesperados:

cd ~/project
nano advanced_expect.exp

Ingrese el siguiente contenido:

#!/usr/bin/expect -f

## Set a timeout
set timeout 10

## Define variables
set program "./multi_prompt.sh"
set max_retries 3
set retry_count 0

## Define a procedure to handle errors
proc handle_error {} {
    global retry_count max_retries program
    incr retry_count

    if {$retry_count < $max_retries} {
        puts "\nRetrying... Attempt $retry_count of $max_retries"
        ## Start the program again
        spawn $program
        return 1
    } else {
        puts "\nMaximum retry attempts reached. Exiting."
        exit 1
    }
}

## Start the program
spawn $program

## Main interaction loop
while {$retry_count < $max_retries} {
    expect {
        "Enter your choice (1-4): " {
            send "1\r"  ## Always choose option 1 for deterministic behavior
        }
        "Invalid option" {
            puts "\nReceived invalid option message."
            if {[handle_error]} continue
        }
        "Current date and time:" {
            ## Successfully got date output
        }
        "Do you want to continue? (yes/no): " {
            send "yes\r"
        }
        "Operation completed successfully." {
            puts "\nAdvanced expect script completed successfully!"
            break
        }
        timeout {
            puts "\nTimeout occurred waiting for prompt."
            if {[handle_error]} continue
        }
        eof {
            puts "\nUnexpected end of file."
            if {[handle_error]} continue
        }
    }
}

## Wait for the program to complete
expect eof

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/advanced_expect.exp

Ejecute el script avanzado:

cd ~/project
./advanced_expect.exp

Ejemplo de salida:

spawn ./multi_prompt.sh
Please select an option:
1. Show date and time
2. List files
3. Show system info
4. Exit
Enter your choice (1-4): 1
Current date and time:
Wed Nov  1 10:00:00 UTC 2023
Do you want to continue? (yes/no): yes
Continuing...
Operation completed successfully.

Advanced expect script completed successfully!

Comprender el script avanzado

Este script avanzado demuestra varias técnicas importantes de expect:

  1. Manejo de errores: Utiliza un mecanismo de reintento para manejar errores o respuestas inesperadas.
  2. Procedimientos: Define un procedimiento personalizado llamado handle_error para el manejo de errores reutilizable.
  3. Flujo de control: Utiliza un bucle while para mantener la interacción hasta el éxito o los reintentos máximos.
  4. Múltiples patrones expect: Maneja múltiples patrones diferentes y toma las acciones apropiadas para cada uno.
  5. Orden de los patrones: El orden de los patrones en el bloque expect es importante: los patrones más específicos deben ir antes que los más generales.

Estas técnicas se pueden aplicar para automatizar programas interactivos complejos donde el flujo puede variar o pueden ocurrir errores.

Creación de scripts expect prácticos para tareas comunes

En este paso, crearemos scripts expect prácticos para tareas comunes que los administradores de sistemas a menudo necesitan automatizar. Nos centraremos en las operaciones de archivos, las interacciones con usuarios y la monitorización del sistema.

Automatización de la transferencia de archivos con expect

Creemos un script expect que automatice la transferencia de un archivo utilizando el comando scp. Dado que no podemos realizar una transferencia de archivos real en este entorno, lo simularemos:

cd ~/project
nano file_transfer.sh

Ingrese el siguiente contenido para simular una transferencia de archivos similar a SCP:

#!/bin/bash

echo "scp file transfer simulation"
echo "Source file: $1"
echo "Destination: $2"
echo "Password: "
read -s password

if [ "$password" == "transfer123" ]; then
  echo "Transferring file..."
  echo "0%"
  sleep 1
  echo "25%"
  sleep 1
  echo "50%"
  sleep 1
  echo "75%"
  sleep 1
  echo "100%"
  echo "File transfer completed successfully."
else
  echo "Authentication failed."
  exit 1
fi

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/file_transfer.sh

Ahora, creemos un script expect para automatizar esta transferencia de archivos:

cd ~/project
nano file_transfer.exp

Ingrese el siguiente contenido:

#!/usr/bin/expect -f

## Set variables
set timeout 10
set source_file "local_file.txt"
set destination "user@remote:/path/to/destination/"
set password "transfer123"

## Create a dummy source file
spawn bash -c "echo 'This is a test file' > $source_file"
expect eof

## Start the file transfer simulation
spawn ./file_transfer.sh $source_file $destination

## Handle the password prompt
expect "Password: "
send "$password\r"

## Monitor the transfer progress
expect "0%"
puts "Transfer started..."

expect "25%"
puts "Transfer 1/4 complete..."

expect "50%"
puts "Transfer 1/2 complete..."

expect "75%"
puts "Transfer 3/4 complete..."

expect "100%"
puts "Transfer almost done..."

expect "File transfer completed successfully."
puts "File transfer automation completed!"

## Clean up the dummy file
spawn bash -c "rm $source_file"
expect eof

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/file_transfer.exp

Ejecute el script de automatización de transferencia de archivos:

cd ~/project
./file_transfer.exp

Ejemplo de salida:

spawn bash -c echo 'This is a test file' > local_file.txt
spawn ./file_transfer.sh local_file.txt user@remote:/path/to/destination/
scp file transfer simulation
Source file: local_file.txt
Destination: user@remote:/path/to/destination/
Password:
Transferring file...
0%
Transfer started...
25%
Transfer 1/4 complete...
50%
Transfer 1/2 complete...
75%
Transfer 3/4 complete...
100%
Transfer almost done...
File transfer completed successfully.
File transfer automation completed!
spawn bash -c rm local_file.txt

Automatización de la creación de usuarios con expect

Ahora, creemos un script expect que automatice la creación de usuarios. Nuevamente, simularemos este proceso:

cd ~/project
nano create_user.sh

Ingrese el siguiente contenido:

#!/bin/bash

echo "User creation utility"
echo "Please enter new username: "
read username

echo "Please enter password for $username: "
read -s password

echo "Please confirm password: "
read -s password_confirm

if [ "$password" != "$password_confirm" ]; then
  echo "Error: Passwords do not match."
  exit 1
fi

echo "Creating user $username..."
echo "User $username created successfully."
echo "Do you want to add this user to the sudo group? (yes/no): "
read sudo_choice

if [ "$sudo_choice" == "yes" ]; then
  echo "Adding $username to sudo group..."
  echo "User $username added to sudo group."
fi

echo "User setup completed."

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/create_user.sh

Ahora, creemos un script expect para automatizar la creación de usuarios:

cd ~/project
nano create_user.exp

Ingrese el siguiente contenido:

#!/usr/bin/expect -f

## Set variables
set timeout 10
set username "testuser"
set password "P@ssw0rd123"
set add_sudo "yes"

## Start the user creation utility
spawn ./create_user.sh

## Handle the username prompt
expect "Please enter new username: "
send "$username\r"

## Handle the password prompt
expect "Please enter password for $username: "
send "$password\r"

## Handle the password confirmation prompt
expect "Please confirm password: "
send "$password\r"

## Wait for the user creation confirmation
expect "User $username created successfully."

## Handle the sudo prompt
expect "Do you want to add this user to the sudo group? (yes/no): "
send "$add_sudo\r"

## If we chose to add to sudo, wait for confirmation
if {$add_sudo == "yes"} {
    expect "User $username added to sudo group."
}

## Wait for completion
expect "User setup completed."

puts "\nUser creation automation completed successfully!"

Guarde el archivo y hágalo ejecutable:

chmod +x ~/project/create_user.exp

Ejecute el script de automatización de creación de usuarios:

cd ~/project
./create_user.exp

Ejemplo de salida:

spawn ./create_user.sh
User creation utility
Please enter new username:
testuser
Please enter password for testuser:
Please confirm password:
Creating user testuser...
User testuser created successfully.
Do you want to add this user to the sudo group? (yes/no):
yes
Adding testuser to sudo group...
User testuser added to sudo group.
User setup completed.

User creation automation completed successfully!

Comprender los scripts expect prácticos

Los scripts prácticos que creamos demuestran varios conceptos importantes para la automatización en el mundo real:

  1. Interacción secuencial: Ambos scripts siguen una secuencia definida de prompts y respuestas.
  2. Monitorización del progreso: El script de transferencia de archivos monitorea el progreso y proporciona actualizaciones fáciles de usar.
  3. Lógica condicional: El script de creación de usuarios utiliza lógica condicional para manejar la opción sudo.
  4. Configuración y limpieza del entorno: El script de transferencia de archivos crea y limpia archivos de prueba.

Estas técnicas se pueden aplicar para automatizar muchas tareas comunes de administración del sistema, como:

  • Copias de seguridad remotas
  • Instalaciones de software
  • Configuración del sistema
  • Operaciones por lotes

Al dominar expect, puede automatizar procesos interactivos complejos que de otro modo requerirían intervención manual, ahorrando tiempo y reduciendo la posibilidad de error humano.

Resumen

En este laboratorio, ha aprendido a usar el comando expect en Linux para automatizar aplicaciones interactivas de línea de comandos. Ha adquirido experiencia práctica con:

  • La instalación y comprensión de la sintaxis básica del comando expect
  • La creación de scripts para automatizar inicios de sesión SSH y manejar varios prompts de autenticación
  • El manejo de múltiples prompts y respuestas en scripts expect
  • La creación de scripts de automatización prácticos para tareas comunes de administración del sistema

El comando expect es una herramienta poderosa para administradores de sistemas y desarrolladores que necesitan automatizar procesos interactivos. Al usar expect, puede eliminar la necesidad de intervención manual en tareas repetitivas, ahorrando tiempo y reduciendo el riesgo de error humano.

Algunas conclusiones clave de este laboratorio:

  • El comando expect utiliza un modelo de patrón-acción para interactuar con los programas
  • Los scripts pueden hacerse más robustos manejando varios prompts posibles y condiciones de error
  • Las interacciones complejas se pueden automatizar utilizando lógica condicional y procedimientos personalizados
  • La automatización práctica puede mejorar significativamente la eficiencia para tareas comunes del sistema

Con las habilidades que ha aprendido en este laboratorio, ahora puede crear sus propios scripts de automatización para varias aplicaciones interactivas de línea de comandos.

Hoja de referencia de comandos de Linux