Bash 脚本中的 Expect

发布于 2024-10-31 01:44:49 字数 878 浏览 2 评论 0原文

我编写了一个包含 Expect 的 Bash 脚本,用于连接到终端服务器并清除线路。

我无法弄清楚我遇到的错误,因为我已经给出了所有必要的大括号。我也不明白无法读取文件“line”:没有这样的文件或目录错误。 我该如何解决这个问题?

我的脚本:

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

I wrote a Bash script with Expect within, to connect to a terminal server and clear lines.

I am unable to figure out the error I am getting, as in I have given all the braces necessary. I also do not understanding the couldn't read file "line": no such file or directory error.
How can I fix this?

My script:

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

Its output:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

稀香 2024-11-07 01:44:49

第一个问题是 shell 不会按照您的意愿解释嵌套双引号。解决此问题的最简单方法是将 Expect 程序放在单引号中。只要 Expect 程序本身没有单引号就足够了。

您将遇到的下一个问题是,将所有模式和操作放在单个 expect 命令中将并行处理它们。实际发生的情况是,第一个 Password: 模式在任何时候看到该字符串时都会匹配(即,即使是第二次的管理员密码)。如果两个密码需要不同,这将是一个问题。至少,相同的模式需要进入单独的 expect 命令,以便可以顺序执行。此问题还会影响 Prompt# 模式,您会查找该模式三次并希望发送三个不同的响应。

稍后,在发送第一个清除命令后,您将收到错误消息。 Expect 解释双引号内的方括号的方式类似于 shell 解释 $()`` (即命令替换)的方式。您将看到如下错误:

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

它正在尝试将 confirm 作为 Tcl(或 Expect)命令运行。您可以使用大括号 ({}) 来阻止 Tcl 进行此解释。此外,默认情况下,期望模式被视为“glob”表达式(即像 shell 通配符),因此即使您编写 {[confirm]} 作为模式,它仍然不会用于精确的表达式。字符串匹配(它将匹配任何单个字符 confi< /code>、rm)。您必须使用 -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"

The first problem is that the shell does not interpret nested double quotes as you might like. The easiest way to fix this is to put the Expect program in single quotes. This will be sufficient as long as there are no single quotes in the Expect program itself.

The next problem you will run into is that having all the patterns and actions in a single expect command will process them in parallel. What is actually happens is that the first Password: pattern will match any time it sees that string (i.e. even for the admin password the second time around). This will be a problem if the two passwords need to be different. At a minimum, identical patterns will need to go into separate expect commands so that they can be executed sequentially. This problem also affects the Prompt# pattern where you look for it three times and want to send three different responses.

Later, you will get an error after you send the first clear command. Expect interprets square brackets inside double quotes in a way that is similar to how shells interpret $() or `` (i.e. command substitution). You will see an error like this:

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

It is trying to run confirm as a Tcl (or Expect) command. You can use curly brackets ({}) to prevent Tcl from making this interpretation. Furthermore, expect patterns are treated as “glob” expressions by default (i.e. like shell wildcards), so even if you write {[confirm]} as the pattern, it will still not be used for an exact string match (it would match any single character c, o, n, f, i, r, or m). You must use the -ex flag to mark the pattern for exact matching.

Fix these issues, drop some of the unnecessary quoting, and you might end up with something like this:

#!/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"
趁年轻赶紧闹 2024-11-07 01:44:49

问题在于 Expect 脚本中的双引号被视为 Expect 脚本的结尾。尝试将单引号与双引号混合:

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

The problem is that that the double quotes in the Expect script are treated as the end of the Expect script. Try mixing single quotes with double quotes:

#!/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" }
}
')
庆幸我还是我 2024-11-07 01:44:49

@Chris:我合并了您建议的更改,我的代码现在正在运行。

但是,我还必须进行以下两项更改:

  1. 您提到的单引号会阻止参数替换。例如,我无法用 $IP 代替 1.1.1.1。因此,为了解决这个问题,我删除了单引号并替换为双引号。正如您提到的,Bash 不会解释嵌套双引号,这是事实。因此我将内部双引号重写为

     发送 \"password1\r\"
    

    即在里面的双引号前添加反斜杠。这纠正了参数替换的问题。

  2. 即使我在一个 Expect 命令中放置了两个/三个操作,因为它们并行运行,我仍然遇到问题。因此,根据您的建议,我将每个操作放在单独的 Expect 命令中。像这样的东西:

    <前><代码>期望{
    提示> { 发送“en\r”; exp_继续 }
    }
    预计 {
    密码:{发送“密码2\r”}
    }

@Chris: I incorporated the changes you suggested and my code is working now.

However, I had to make two more changes stated below:

  1. The single quote which you mentioned prevents parameter substitution. For example, I cannot write $IP in place of 1.1.1.1. Hence, to get around this, I removed the single quotes and replaced with double quotes. As you mentioned nested doubles quotes are not interpreted by Bash which is true. Hence I rewrote the inside double quotes as

     send \"password1\r\"
    

    That is adding backslashes before the double quotes inside. This corrects the problem of parameter substitution.

  2. Even after I put two/three actions within a single expect command, as they run in parallel I still faced issues. So taking your suggestion, I put each of the action in a separate Expect command. Something like:

     expect {
         Prompt>          { send "en\r"; exp_continue }
     }
     expect  {
         Password:        { send "password2\r" }
     }
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文