0

我正在尝试 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"
...

我收到以下错误消息:# invalid command name "!" 在执行从内部调用的“!-f /root/.ssh/id_rsa.pub ”时

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

4

4 回答 4

4

您需要转义方括号,因为它是 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

于 2013-04-03T06:55:44.000 回答
1

正如 slebetman 已经指出的那样,字符[, ],$\内部具有特殊含义"

  • [and]用于命令替换,因此[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"

或使用{and}包围你的字符串。
如果您使用{并且}不会进行替换。这也包括\r将被发送\r到服务器,而不是作为单个字符。

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

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

    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@@}]
    

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

于 2013-04-03T13:34:39.607 回答
0

你的里面有什么$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
"
于 2013-04-03T00:55:06.187 回答
0

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

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

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

于 2013-04-03T02:00:40.583 回答