在 proc 内运行 proc 时 Expect 失败

mes*_*600 4 unix bash tcl expect

当使用一个进程时,我的脚本工作正常(检索 sftp 提示)。但是当我尝试在 proc 内部使用 proc 时,脚本被卡住,我不知道为什么。

请不要重构代码,这不是重点,我需要了解这里的问题是什么。

工作代码:

proc sftp_connect {} {
  set times 0;
  set connection_retry 2
  set timeout 1;
  while { $times < $connection_retry } {
    spawn sftp ${SFTP_USER}@${SFTP_SERVER}
    expect {
      timeout { puts "Connection timeout"; exit 1}
      default {exit 2}
      "*assword:*" { 
        send "${SFTP_PASSWORD}\n";
        expect {
          "sftp>" { puts "Connected"; set times [ expr $times+1]; exp_continue}
        }
      }
    }
  }
  send "quit\r";
}

sftp_connect
Run Code Online (Sandbox Code Playgroud)

调试输出:

expect: does "\r\nsftp> " (spawn_id exp5) match glob pattern "sftp>"? yes
Run Code Online (Sandbox Code Playgroud)

但是将发送密码移至单独的过程后,expect 不再检索 sftp 提示(“sftp>”):

proc sftp_send_password {} {
  send "${SFTP_PASSWORD}\n";
  expect {
    "sftp>" { puts "Connected"; set times [ expr $times+1]; exp_continue}
  }
}

proc sftp_connect {} {
  set times 0;
  set connection_retry 2
  set timeout 1;
  while { $times < $connection_retry } {
    spawn sftp ${SFTP_USER}@${SFTP_SERVER}
    expect {
      timeout { puts "Connection timeout"; exit 1}
      default {exit 2}
      "*assword:*" { sftp_send_password }
    }
  }
  send "quit\r";
}

sftp_connect
Run Code Online (Sandbox Code Playgroud)

调试输出:

expect: does "" (spawn_id exp0) match glob pattern "sftp>"? yes
Run Code Online (Sandbox Code Playgroud)

gle*_*man 5

我手边没有“探索期望”的副本,但我认为您遇到了变量范围问题。spawn无形地设置了一个名为 的变量spawn_id。当您在过程中调用 spawn 时,该变量的作用域仅适用于该过程。将其声明为全局:

proc sftp_connect {} {
  global spawn_id
  # ... rest is the same
}
Run Code Online (Sandbox Code Playgroud)

我认为你不必做同样的事情,sftp_send_password因为expect有比Tcl更宽容的范围方案(如果expect没有找到局部变量,请在全局命名空间中查找)。

由于相同的变量作用域问题,您的sftp_send_password过程不会影响times其中的变量。sftp_connect我会推荐

proc sftp_send_password {times_var} {
  upvar 1 $times_var times     ;# link this var to that in the caller
  send "${SFTP_PASSWORD}\n";
  expect {
    "sftp>" { puts "Connected"; incr times; exp_continue} 
  }
  # note use of `incr` instead of `expr`
}
Run Code Online (Sandbox Code Playgroud)

然后sftp_connect过程发送times变量名称

sftp_send_password times
Run Code Online (Sandbox Code Playgroud)