Comando expect do Linux com Exemplos Práticos

LinuxBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá como usar o comando expect do Linux para automatizar aplicações interativas de linha de comando. O comando expect é uma ferramenta de automação poderosa que permite que scripts interajam com programas que exigem entrada do usuário, como SSH, FTP e outros programas interativos.

Ao final deste laboratório, você será capaz de:

  • Compreender o propósito e a sintaxe básica do comando expect
  • Criar scripts para automatizar logins SSH
  • Lidar com vários prompts e respostas em seus scripts expect

O comando expect pode reduzir significativamente a intervenção manual para tarefas repetitivas, tornando a administração de sistemas e tarefas de rotina mais eficientes. Você começará instalando e explorando a sintaxe básica do expect, e então progredirá para a criação de scripts para automatizar logins SSH e lidar com vários prompts interativos.

Folha de Dicas de Comandos Linux

Compreendendo o Comando expect e Sua Sintaxe Básica

O comando expect no Linux permite que você automatize programas interativos de linha de comando que normalmente exigem entrada do usuário. Isso é particularmente útil para tarefas como logins automatizados, transferências de arquivos ou qualquer situação em que um programa solicita entrada.

Instalando o expect

Primeiramente, vamos verificar se o pacote expect está instalado em nosso sistema. Abra seu terminal e execute:

which expect

Se o expect já estiver instalado, você verá seu caminho (como /usr/bin/expect). Caso contrário, você precisará instalá-lo:

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

Compreendendo a Sintaxe Básica do expect

O comando expect usa uma linguagem de script baseada em Tcl (Tool Command Language). A estrutura básica de um script expect inclui os seguintes comandos:

  1. spawn: Inicia um processo para interagir
  2. expect: Aguarda uma saída específica do processo gerado
  3. send: Envia entrada para o processo gerado
  4. set timeout: Define quanto tempo esperar pela saída esperada

Vamos criar um script expect simples para demonstrar esses conceitos. Abra um editor de texto e crie um arquivo chamado hello.exp em seu diretório de projeto:

cd ~/project
nano hello.exp

Digite o seguinte conteúdo no arquivo:

#!/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

Salve o arquivo pressionando Ctrl+O, depois Enter e saia do nano com Ctrl+X.

Torne o script executável:

chmod +x ~/project/hello.exp

Agora execute o script:

~/project/hello.exp

Você deve ver uma saída semelhante a esta:

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

Compreendendo Cada Linha do Script

Deixe-me explicar o que cada linha do script faz:

  • #!/usr/bin/expect -f: Esta é uma linha shebang que diz ao sistema para usar o interpretador expect para executar este script.
  • set timeout 10: Isso define um tempo limite de 10 segundos para qualquer comando expect que se seguir.
  • spawn bash: Isso inicia um novo processo de shell bash com o qual expect irá interagir.
  • expect "$ ": Isso aguarda o aparecimento do prompt bash.
  • send "echo Hello from expect\r": Isso envia o comando para o shell bash. Observe o \r no final, que simula pressionar Enter.
  • expect "$ ": Isso aguarda o prompt bash novamente, após o comando ter sido executado.
  • send "exit\r": Isso envia o comando exit para fechar o shell bash.
  • expect eof: Isso aguarda a terminação do processo gerado.

Este exemplo simples demonstra a funcionalidade principal do expect. Nos próximos passos, usaremos esses conceitos para criar scripts mais práticos.

Criando um Script de Login SSH Falso com expect

Nesta etapa, criaremos um script expect que simula um processo de login SSH. Como não podemos realizar um login SSH real neste ambiente, criaremos um script falso que demonstra os princípios.

Compreendendo o Fluxo de Autenticação SSH

Ao conectar-se a um servidor remoto via SSH, a interação típica envolve:

  1. Iniciar a conexão com ssh username@hostname
  2. Aceitar a chave do host (se conectando pela primeira vez)
  3. Inserir sua senha quando solicitado
  4. Obter acesso ao shell remoto

Vamos criar um ambiente SSH falso para demonstrar como o expect pode automatizar este processo.

Criando um Script de Servidor SSH Falso

Primeiro, vamos criar um script que simula um servidor SSH solicitando uma senha:

cd ~/project
nano mock_ssh_server.sh

Insira o seguinte conteúdo:

#!/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

Salve o arquivo e torne-o executável:

chmod +x ~/project/mock_ssh_server.sh

Este script simula:

  • O prompt de verificação do host SSH
  • O prompt de senha
  • Um shell simples que responde a comandos

Criando um Script expect para Automatizar o Login

Agora, vamos criar um script expect que automatiza a interação com nosso servidor SSH falso:

cd ~/project
nano ssh_login.exp

Insira o seguinte conteúdo:

#!/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!"

Salve o arquivo e torne-o executável:

chmod +x ~/project/ssh_login.exp

Executando o Script de Login Automatizado

Agora, vamos executar nosso script expect para automatizar a interação com o servidor SSH falso:

cd ~/project
./ssh_login.exp

Você deve ver uma saída semelhante 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!

Explicando o Script

Deixe-me explicar o que cada parte do nosso script expect faz:

  1. set timeout 10: Define um tempo limite global de 10 segundos para todos os comandos expect.
  2. set password "mockpassword": Armazena a senha em uma variável.
  3. spawn ./mock_ssh_server.sh: Inicia nosso script de servidor SSH falso.
  4. expect "Are you sure you want to continue connecting (yes/no)? ": Aguarda o prompt de verificação do host.
  5. send "yes\r": Envia "yes" para aceitar a chave do host.
  6. expect "Password: ": Aguarda o prompt de senha.
  7. send "$password\r": Envia a senha.
  8. expect "mockuser@mockserver:~$ ": Aguarda o prompt do shell.
  9. send "ls -la\r": Envia um comando para listar arquivos.
  10. expect "mockuser@mockserver:~$ ": Aguarda o prompt do shell novamente.
  11. send "exit\r": Envia o comando exit para fechar a sessão.
  12. expect eof: Aguarda a terminação do processo.
  13. puts "\nSSH login automation completed successfully!": Imprime uma mensagem de sucesso.

Este exemplo demonstra como o expect pode ser usado para automatizar todo o processo de login SSH, desde aceitar a chave do host até executar comandos no servidor remoto e sair com segurança.

Lidando com Múltiplos Prompts e Respostas com expect

Em cenários do mundo real, programas interativos frequentemente apresentam múltiplos prompts e podem exigir diferentes respostas com base em diferentes condições. Nesta etapa, aprenderemos como lidar com múltiplos prompts e respostas condicionais em scripts expect.

Compreendendo os Blocos expect Condicionais

O comando expect pode ser usado com uma estrutura de bloco de padrão-ação para lidar com diferentes prompts possíveis:

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

Esta estrutura permite que seu script responda de forma diferente dependendo da saída que recebe.

Criando um Script de Manipulação de Múltiplos Prompts

Vamos criar um script que simula um programa com múltiplos prompts:

cd ~/project
nano multi_prompt.sh

Insira o seguinte conteúdo:

#!/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

Salve o arquivo e torne-o executável:

chmod +x ~/project/multi_prompt.sh

Agora, vamos criar um script expect para interagir com este programa e lidar com todos os prompts possíveis:

cd ~/project
nano handle_prompts.exp

Insira o seguinte conteúdo:

#!/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!"

Salve o arquivo e torne-o executável:

chmod +x ~/project/handle_prompts.exp

Executando o Script de Manipulação de Múltiplos Prompts

Agora, vamos executar nosso script expect para interagir com o programa de múltiplos prompts:

cd ~/project
./handle_prompts.exp

Cada vez que você executar este script, ele selecionará aleatoriamente uma das opções e decidirá aleatoriamente se deve continuar ou sair. Aqui está um exemplo de saída:

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!

Criando um Script expect Mais Avançado

Agora, vamos criar um script mais avançado que pode lidar com prompts e erros inesperados:

cd ~/project
nano advanced_expect.exp

Insira o seguinte conteúdo:

#!/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

Salve o arquivo e torne-o executável:

chmod +x ~/project/advanced_expect.exp

Execute o script avançado:

cd ~/project
./advanced_expect.exp

Exemplo de saída:

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!

Compreendendo o Script Avançado

Este script avançado demonstra várias técnicas importantes do expect:

  1. Tratamento de erros: Ele usa um mecanismo de repetição para lidar com erros ou respostas inesperadas.
  2. Procedimentos: Ele define um procedimento personalizado chamado handle_error para tratamento de erros reutilizável.
  3. Fluxo de controle: Ele usa um loop while para manter a interação até o sucesso ou o número máximo de tentativas.
  4. Múltiplos padrões expect: Ele lida com múltiplos padrões diferentes e toma as ações apropriadas para cada um.
  5. Ordem dos padrões: A ordem dos padrões no bloco expect é importante - padrões mais específicos devem vir antes dos mais gerais.

Essas técnicas podem ser aplicadas para automatizar programas interativos complexos onde o fluxo pode variar ou erros podem ocorrer.

Criando Scripts expect Práticos para Tarefas Comuns

Nesta etapa, criaremos scripts expect práticos para tarefas comuns que os administradores de sistema frequentemente precisam automatizar. Focaremos em operações de arquivos, interações com usuários e monitoramento do sistema.

Automatizando a Transferência de Arquivos com expect

Vamos criar um script expect que automatiza a transferência de um arquivo usando o comando scp. Como não podemos realizar uma transferência de arquivo real neste ambiente, vamos simulá-la:

cd ~/project
nano file_transfer.sh

Insira o seguinte conteúdo para simular uma transferência de arquivo semelhante ao 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

Salve o arquivo e torne-o executável:

chmod +x ~/project/file_transfer.sh

Agora, vamos criar um script expect para automatizar esta transferência de arquivo:

cd ~/project
nano file_transfer.exp

Insira o seguinte conteúdo:

#!/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

Salve o arquivo e torne-o executável:

chmod +x ~/project/file_transfer.exp

Execute o script de automação de transferência de arquivos:

cd ~/project
./file_transfer.exp

Exemplo de saída:

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

Automatizando a Criação de Usuários com expect

Agora, vamos criar um script expect que automatiza a criação de usuários. Novamente, vamos simular este processo:

cd ~/project
nano create_user.sh

Insira o seguinte conteúdo:

#!/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."

Salve o arquivo e torne-o executável:

chmod +x ~/project/create_user.sh

Agora, vamos criar um script expect para automatizar a criação de usuários:

cd ~/project
nano create_user.exp

Insira o seguinte conteúdo:

#!/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!"

Salve o arquivo e torne-o executável:

chmod +x ~/project/create_user.exp

Execute o script de automação de criação de usuários:

cd ~/project
./create_user.exp

Exemplo de saída:

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!

Compreendendo os Scripts expect Práticos

Os scripts práticos que criamos demonstram vários conceitos importantes para a automação do mundo real:

  1. Interação Sequencial: Ambos os scripts seguem uma sequência definida de prompts e respostas.
  2. Monitoramento de Progresso: O script de transferência de arquivos monitora o progresso e fornece atualizações amigáveis ao usuário.
  3. Lógica Condicional: O script de criação de usuários usa lógica condicional para lidar com a opção sudo.
  4. Configuração e Limpeza do Ambiente: O script de transferência de arquivos cria e limpa arquivos de teste.

Essas técnicas podem ser aplicadas para automatizar muitas tarefas comuns de administração de sistema, como:

  • Backups remotos
  • Instalações de software
  • Configuração do sistema
  • Operações em lote

Ao dominar o expect, você pode automatizar processos interativos complexos que, de outra forma, exigiriam intervenção manual, economizando tempo e reduzindo o potencial de erro humano.

Resumo

Neste laboratório, você aprendeu como usar o comando expect no Linux para automatizar aplicações interativas de linha de comando. Você adquiriu experiência prática com:

  • Instalação e compreensão da sintaxe básica do comando expect
  • Criação de scripts para automatizar logins SSH e lidar com vários prompts de autenticação
  • Lidar com múltiplos prompts e respostas em scripts expect
  • Criação de scripts de automação práticos para tarefas comuns de administração de sistema

O comando expect é uma ferramenta poderosa para administradores de sistema e desenvolvedores que precisam automatizar processos interativos. Ao usar expect, você pode eliminar a necessidade de intervenção manual em tarefas repetitivas, economizando tempo e reduzindo o risco de erro humano.

Alguns pontos-chave deste laboratório:

  • O comando expect usa um modelo de padrão-ação para interagir com programas
  • Scripts podem ser tornados mais robustos lidando com vários prompts possíveis e condições de erro
  • Interações complexas podem ser automatizadas usando lógica condicional e procedimentos personalizados
  • A automação prática pode melhorar significativamente a eficiência para tarefas comuns do sistema

Com as habilidades que você aprendeu neste laboratório, você pode agora criar seus próprios scripts de automação para várias aplicações interativas de linha de comando.

Linux Commands Cheat Sheet