Помогите с Expect в скрипте bash - PullRequest
10 голосов
/ 07 апреля 2011

Я написал 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 ]

20 голосов
/ 07 апреля 2011

Первая проблема заключается в том, что оболочка не интерпретирует вложенные двойные кавычки, как вам может понадобиться. Самый простой способ исправить это - поместить программу 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"
3 голосов
/ 07 апреля 2011

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

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

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

send \"password1\r\" 

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

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

expect {  
    Prompt>          { send "en\r"; exp_continue }  
}  
expect  {  
    Password:        { send "password2\r" }  
} 
1 голос
/ 07 апреля 2011

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

Комментарий о вашем ожидаемом стиле сценария: ваши команды ожидают / отправляют линейные, поэтому кажется странным иметь один блок ожидаемых и несколько операторов 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
')
1 голос
/ 07 апреля 2011

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

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