【问题标题】:Expect / Bash: Running a bash if statement in expectExpect / Bash:在expect中运行bash if语句
【发布时间】:2013-04-03 21:34:39
【问题描述】:

我正在尝试通过 ssh 连接到服务器,并检查 id_rsa.pub 是否存在。如果它不存在,我想运行 ssh-keygen,否则我什么都不想做。

我可以在 Tcl/Expect 中使用 send 运行简单的命令,如“cat”或“rm”,但是当我尝试执行类似操作时,它不起作用:

send "if [ ! -f $USER_SSH_PATH/id_rsa.pub ]; then CREATE_FILE=true; fi\r"
expect "# " { }

send "if $CREATE_FILE; then; ssh-keygen -t rsa -C $USER -f $USER_SSH_PATH/id_rsa\r"
...

我收到以下错误消息: # 无效的命令名“!” 在执行时 “!-f /root/.ssh/id_rsa.pub” 从内部调用

请问可以运行这样的命令吗?

【问题讨论】:

    标签: bash scripting tcl expect


    【解决方案1】:

    您需要转义方括号,因为它是 tcl 语法的一部分:

    send "if \[ ! -f $USER_SSH_PATH/id_rsa.pub \]; then CREATE_FILE=true; fi\r"
    

    在 tcl 中,[] 的工作方式与 ``$() 在 bash 中的工作方式相同。所以发生的事情是,在执行 send 命令之前,解释器首先对字符串进行替换,它会看到需要替换的两件事:

    1. $USER_SSH_PATH 被变量 USER_SSH_PATH 中包含的值替换

    2. [! ....] 被调用! 函数/命令的结果替换。正如你所发现的那样不存在。

    请注意,在 tcl(以及扩展期望)中,变量和函数名称不限于字母数字。变量和函数名称如$! 甚至是NUL 字符(值为0 的字节)都是有效的:

    proc ! {} {puts "!"}
    proc "$" {} {puts "\$"}
    proc \0 {} {puts "NUL character"}
    
    !   ;# this prints !
    \$  ;# this prints $
    \0  ;# this prints "NUL character"
    

    有关 tcl 语法的更多信息,请参阅http://www.tcl.tk/man/tcl/TclCmd/Tcl.htm

    【讨论】:

    • 这是唯一真正解决问题的答案。
    • 谢谢!这实际上是我需要的,你解决了我的问题!非常感谢!
    【解决方案2】:

    正如 slebetman 已经指出的,字符 []$\" 中具有特殊含义。

    • [] 用于命令替换,因此 [expr {2+3}] 将替换为 5(结果)。
    • $ 用于变量替换。
    • \ 用于特殊字符(如\r 用于代码点为 13 的字符)

    您可以使用\ 转义" 中的这些字符:我假设$USER_SSH_PATH 是一个本地(tcl)变量

    send "if \[ ! -f $USER_SSH_PATH/id_rsa.pub \]; then CREATE_FILE=true; fi\r"
    

    或使用{} 包围您的字符串。
    如果您使用{},则不会进行任何替换。这还包括\r 将作为\r 发送到服务器,而不是作为单个字符。

    还有其他几个选项可以创建这样的东西:

    • subst 可以对字符串进行替换。也有可能只发生某些类型的替换(使用-nocommands 开关来防止[] 替换,-novariables 用于$ 替换和-nobackslashes 用于\
      示例:

      send [subst -nocommands \
          {if [ ! -f $USER_SSH_PATH/id_rsa.pub ]; then CREATE_FILE=true; fi\r}]
      
    • string map 替换某些序列。
      示例

      send [string map [list {@@r@@} \r {@@USER_SSH_PATH@@} $USER_SSH_PATH] \
         {if [ ! -f @@USER_SSH_PATH@@/id_rsa.pub ]; then CREATE_FILE=true; fi@@r@@}]
      

    有很多方法可以做这样的事情。

    【讨论】:

    • 谢谢!这很有帮助!谢谢。
    【解决方案3】:

    您的 $USER_SSH_PATH 中有什么内容?在你的本地和远程机器上是不是一样的,也就是说你有正确的权限...下面可能会帮助你调试。

    echo ${USER_SSH_PATH}
    ssh <hostname> "
    if [ ! -f ${USER_SSH_PATH}/id_rsa.pub ]; then
       echo ${USER_SSH_PATH};
       echo \"File Not Found, Creating....\";
       ssh-key-gen -t rsa -C ${USER} -f ${USER_SSH_PATH}/id_rsa;
    else
       echo \"File Found\";
       exit 1;
    fi
    "
    

    【讨论】:

    • $USER_SSH_PATH 实际上只是 /root/.ssh,谢谢!我首先在服务器上以 root 身份登录。我必须使用 expect 登录,第一次没有设置 ssh-keygen。
    • 我不确定您的评论对我有什么帮助,我只是想让 if 语句与 expect 一起发送。
    • 我在这里写的行将在远程服务器上的ssh 上执行if statements,检查id_rsa.pub。如果文件不存在,它将执行您的ssh-keygen 命令。我不明白你想用send 实现什么额外的目标?
    • 如果需要,我使用 expect 来发送密码。之前执行了一堆“期望”和“发送”,看看是否需要密码。因此,您的解决方案将不起作用。
    • 这不太可能做正确的事。如果在 bash 中完成,则不能解决问题。如果按预期完成,它会遇到与原始问题相同的问题。
    【解决方案4】:

    我刚刚想到的一个解决方案是在发送中运行“ls /root/.ssh/ | grep id_rsa.pub”,然后使用期望查看输出。我很好奇我怎么能运行 bash if 命令。

    要么我得到“id_rsa.pub”作为回报,要么空行。但如果我有“id_rsa.pub*”,它就会坏掉。

    请问有人有改进的想法吗?谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-09
      • 1970-01-01
      • 2017-09-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多