【问题标题】:Get one line of user input and then execute it as Bash commands获取一行用户输入,然后将其作为 Bash 命令执行
【发布时间】:2015-09-08 03:22:27
【问题描述】:

我写了一个期望脚本,帮助在远程机器上执行命令。执行完成后,我想获取一行用户输入,然后发送到远程bash,这里是sn -p的代码:

#! /usr/bin/env expect
...
spawn ssh -l $user $host
...
send_tty -- "Enter your command: " 
set timeout -1

# match only printable characters (prevent from pressing TAB)
expect_tty eof exit -re {([[:print:]]*)\n}
send_tty -- "\n"
set timeout 10

# send the command to remote shell
send "$expect_out(1,string)" 
expect "$GENERAL_PROMPT"

但是,如果输入类似于:ls /",我的程序将被阻止,因为远程 shell 期望通过提示字符串“>”来获取更多字符。实际上,我希望 bash 不会提示输入更多信息,而不仅仅是打印错误消息:

$ read COMMAND
ls /"
$ eval "$COMMAND"
bash: unexpected EOF while looking for matching `"'
bash: syntax error: unexpected end of file

我可以在我的脚本中实现这一点吗?

【问题讨论】:

  • @ zhujs :我不是 bash 专家,但是,当我尝试使用ls /" 作为输入和eval $COMMAND 执行read COMMAND 时,我在终端中得到了上述错误。如果输入没有双引号,即ls /,那么它工作正常。
  • 我只想让我的脚本在用户输入ls /"时打印出同样的错误
  • 使用eval,就像你尝试过的一样。
  • 使用多提示。 set multiPrompt {[>\"] }
  • @whjm 我试过这个命令:send "eval $expect_out(1,string)",但我的程序还是被阻塞了

标签: linux bash expect


【解决方案1】:
#!/usr/bin/expect
set prompt "#|%|>|\\\$ $"; # A generalized prompt to match known prompts.
spawn ssh -l dinesh xxx.xx.xx.xxx
expect {
    "(yes/no)" { send "yes\r";exp_continue}
    "password" 
}
send "mypassword\r"
expect -re $prompt
send_tty -- "Enter your command: " 
set timeout -1

# match only printable characters (prevent from pressing TAB)
expect_tty eof exit -re {([[:print:]]*)\n}
send_tty -- "\n"
set timeout 10
puts "\nUSER INPUT : $expect_out(1,string)"

# send the command to remote shell 
# Using 'here-doc', to handle possible user inputs, instead of quoting it with any other symbol like single quotes or backticks
send "read COMMAND <<END\r"
expect -re $prompt
send "$expect_out(1,string)\r" 
expect -re $prompt
send "END\r"
expect -re $prompt

# Since we want to send the literal dollar sign, I am sending it within braces
send {eval $COMMAND}
# Now sending 'Return' key
send "\r"
expect -re $prompt

为什么使用“here-doc”?

如果我使用反引号或单引号来转义命令,那么如果用户在命令本身中给出反引号或单引号,那么它可能会失败。所以,为了克服这个问题,我添加了 here-doc。

输出:

dinesh@MyPC:~/stackoverflow$ ./zhujs
spawn ssh -l dinesh xxx.xx.xx.xxx
dinesh@xxx.xx.xx.xxx's password: 

[dinesh@lab ~]$ matched_literal_dollar_sign
Enter your command: ls /"


USER INPUT : ls /"
read COMMAND <<END
> ls /"
> END
[dinesh@lab ~]$ eval $COMMAND
-bash: unexpected EOF while looking for matching `"'
-bash: syntax error: unexpected end of file
[dinesh@lab ~]$ dinesh@MyPC:~/stackoverflow$ 

更新:

使用here-doc 的主要原因是它使读取充当非阻塞命令。即我们可以快速执行下一个命令。否则,我们必须等到Expect 超时。 (当然,我们可以动态更改超时值。)

这只是一种方法。您可以根据需要更改它,只需使用read 命令。

【讨论】:

  • 哇,看来行得通,你能用一个例子解释一下你的Why 'here-doc' used吗?
  • 更新了输出。希望对您有所帮助。
  • "如果我使用了反引号或单引号来转义命令,那么如果用户在命令本身中给出了反引号或单引号,那么它可能会失败。"这是什么意思?
  • @zhujs : 如果没有here-doc,命令可以评估为eval '&lt;cmd&gt;'。如果用户以ls /" 给出命令,它将抛出预期的错误消息。但是,如果假设用户在命令本身中给出单引号,即ls ',那么在评估期间它将变为eval 'ls '',这使得它等待其余的命令。同样的事情也适用于反引号。 (我不能在这里给出反引号的例子,因为 stackoverflow 对 code 格式的文本使用反引号;-))希望你明白了。
  • 没有here-doc,expect 会被阻塞,因为read 命令会要求更多的输入,而不是bash。不过her-doc 版本对我有用,谢谢!
【解决方案2】:

我认为这对于interact 来说是一个很好的案例——期待让位,让用户直接与生成的程序进行交互。

spawn ssh -l $user $host
#...

send_user "You are now about to take control: type QQQ to return control to the program\n"

interact {
    QQQ   return
}

send_user "Thanks, I'm back in charge ...\n"

【讨论】:

    【解决方案3】:

    这是一个单行版本

    read &gt; export cmd ; eval $cmd ; unset cmd

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-29
      • 2013-01-01
      相关资源
      最近更新 更多