Помогите с Expect в скрипте bash

Я написал сценарий bash с ожидаемым внутри, чтобы подключиться к терминальному серверу и очистить линии. Я не могу понять, какую ошибку я получаю, так как я дал все необходимые скобки. Я тоже не понимаю couldn't read file "line": no such file or directory ошибка. Пожалуйста, помогите.

Мой сценарий:

#!/bin/bash  
VAR=$(expect -c "  
spawn telnet 1.1.1.1   
expect {  
       "Password:" { send "password\r" ; exp_continue}  
       "Prompt>" { send "en\r" ; exp_continue}  
       "Password:" { send "password\r" ; exp_continue}  
       "Prompt#" {send "clea line 10\r" ; exp_continue}  
       "[confirm]" {send "Y\r" ; exp_continue}  
       "Prompt#" {send "clea line 11\r" ; exp_continue}  
       "[confirm]" {send "Y\r" ; exp_continue}  
       "Prompt#" {send "exit\r" }  
    }  
")  

echo $VAR  

Его вывод:

missing close-brace  
    while executing  
"expect"  
couldn't read file "line": no such file or directory  

4 ответа

Решение

Первая проблема заключается в том, что оболочка не интерпретирует вложенные двойные кавычки, как вам может понравиться. Самый простой способ исправить это - поместить программу Expect в одинарные кавычки. Этого будет достаточно, если в самой программе Expect нет одинарных кавычек.

Следующая проблема, с которой вы столкнетесь, состоит в том, что все шаблоны и действия в одном expect Команда будет обрабатывать их параллельно. На самом деле происходит то, что первый Password: Шаблон будет совпадать каждый раз, когда он видит эту строку (т.е. даже для пароля администратора во второй раз). Это будет проблемой, если два пароля должны быть разными. Как минимум, идентичные шаблоны должны будут expect Команды, чтобы они могли выполняться последовательно. Эта проблема также влияет на Prompt# шаблон, где вы ищете его три раза и хотите отправить три разных ответа.

Позже вы получите сообщение об ошибке после отправки первой команды очистки. Expect интерпретирует квадратные скобки внутри двойных кавычек так, как интерпретирует оболочка $() или же `` (т.е. подстановка команды). Вы увидите ошибку, подобную этой:

invalid command name "confirm"
    while executing
"confirm"
    invoked from within
"expect {  
⋮

Пытается запустить confirm как команда Tcl (или Expect). Вы можете использовать фигурные скобки ({}) чтобы Tcl не сделал эту интерпретацию. Более того, ожидаемые шаблоны по умолчанию обрабатываются как "глобальные" выражения (то есть как подстановочные знаки оболочки), так что даже если вы пишете {[confirm]} как образец, он все еще не будет использоваться для точного соответствия строки (он будет соответствовать любому отдельному символу c, o, n, f, i, r, или же m). Вы должны использовать -ex флаг, чтобы отметить шаблон для точного соответствия.

Исправьте эти проблемы, отбросьте ненужные цитаты, и вы можете получить что-то вроде этого:

#!/bin/sh
VAR=$(expect -c '
  proc abort {} {
    puts "Timeout or EOF\n"
    exit 1
  }
  spawn telnet 1.1.1.1
  expect {
    Password:        { send "password1\r" }
    default          abort
  }
  expect {
    Prompt>          { send "en\r"; exp_continue }
    Password:        { send "password2\r" }
    default          abort
  }
  expect {
    Prompt#          { send "clea line 10\r"; exp_continue }
    -ex {[confirm]}  { send "Y\r" }
    default          abort
  }
  expect {
    Prompt#          { send "clea line 11\r"; exp_continue }
    -ex {[confirm]}  { send "Y\r" }
    default          abort
  }
  expect {
    Prompt#          { send "exit\r"; exp_continue }
    timeout          abort
    eof
  }
  puts "Finished OK\n"
')

echo "$VAR"

Проблема в том, что двойные кавычки в ожидаемом сценарии рассматриваются как конец ожидаемого сценария. Попробуйте смешать одинарные и двойные кавычки:

#!/bin/bash
VAR=$(expect -c '
spawn telnet 1.1.1.1
expect {
"Password:" { send "password\r" ; exp_continue}
"Prompt>" { send "en\r" ; exp_continue}
"Password:" { send "password\r" ; exp_continue}
"Prompt#" {send "clea line 10\r" ; exp_continue}
"[confirm]" {send "Y\r" ; exp_continue}
"Prompt#" {send "clea line 11\r" ; exp_continue}
"[confirm]" {send "Y\r" ; exp_continue}
"Prompt#" {send "exit\r" }
}
')

@Chris: я включил предложенные вами изменения, и мой код работает.

Однако мне пришлось внести еще два изменения, указанные ниже:

1] Одиночная кавычка, которую вы упомянули, предотвращает подстановку параметров. Например я не могу написать $IP на месте 1.1.1.1, Следовательно, чтобы обойти это, я удалил одинарные кавычки и заменил их двойными. Как вы упомянули, вложенные двойные кавычки не интерпретируются bash, что верно. Поэтому я переписал внутренние двойные кавычки как

send \"password1\r\" 

Это добавляет обратную косую черту перед двойными кавычками внутри. Это исправляет проблему подстановки параметров.

2] Даже после того, как я поместил два / три действия в одну ожидаемую команду, поскольку они выполняются параллельно, я все еще сталкивался с проблемами. Поэтому, принимая ваше предложение, я поместил каждое действие в отдельную команду ожидающих. Что-то вроде

expect {  
    Prompt>          { send "en\r"; exp_continue }  
}  
expect  {  
    Password:        { send "password2\r" }  
} 

@ Дэвид имеет правильный ответ.

Комментарий о вашем стиле ожидаемого сценария: ваши команды ожидают / отправляют линейные, поэтому кажется странным иметь один блок ожидаемых и несколько операторов exp_continue. Было бы проще написать это:

VAR=$(expect -c '
  spawn telnet 1.1.1.1
  expect "Password:"
  send "password\r"
  expect "Prompt>"
  send "en\r"
  expect "Password:"
  send "password\r" 
  expect "Prompt#"
  send "clea line 10\r" 
  expect "[confirm]"
  send "Y\r" 
  expect "Prompt#"
  send "clea line 11\r"
  expect "[confirm]"
  send "Y\r" 
  expect "Prompt#"
  send "exit\r" 
  expect eof
')
Другие вопросы по тегам