简体   繁体   English

获取一行用户输入,然后将其作为 Bash 命令执行

[英]Get one line of user input and then execute it as Bash commands

I have wrote a expect script that helps to execute commands in remote machine.我写了一个期望脚本,有助于在远程机器上执行命令。 When the execution is completed, I want to get one line of user input and then send it to the remote bash, here is the code snippet:执行完成后,我想获取一行用户输入,然后将其发送到远程 bash,这是代码片段:

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

However, if the input is something like: ls /" , my program will be blocked because the remote shell expects to get more characters by prompting the string "> ". Actually, I hope bash won't prompt for more input instead of just printing error message:但是,如果输入类似于: ls /" ,我的程序将被阻止,因为远程shell希望通过提示字符串 "> " 来获取更多字符。实际上,我希望 bash 不会提示更多输入,而不仅仅是打印错误信息:

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

Can I achieve this in my script?我可以在我的脚本中实现这一点吗?

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

Why 'here-doc' used ?为什么使用“here-doc”?

If I have used backticks or single quotes to escape the commands, then if user gave backticks or single quotes in the commands itself, then it may fail.如果我使用反引号或单引号来转义命令,那么如果用户在命令本身中使用反引号或单引号,则它可能会失败。 So, to overcome that only, I have added here-doc.所以,为了克服这个问题,我添加了 here-doc。

Output :输出 :

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$ 

Update :更新 :

The main reason for using here-doc is due to the fact that it makes the read to act as non-blocking command.使用here-doc主要原因是它使读取充当非阻塞命令。 ie We can proceed quickly with next command.即我们可以快速进行下一个命令。 Else, we have to wait till the timeout of Expect .否则,我们必须等到Expect超时。 (Of course, we could change the timeout value dynamically.) (当然,我们可以动态更改超时值。)

This is just one way of doing it.这只是一种方法。 You can alter it if you want, with simply having the read command.您可以根据需要更改它,只需使用read命令即可。

I think this would be a good case for interact -- get expect to step aside and let the user interact directly with the spawned program.我认为这将是一个很好的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"

这是一个单行版本

read > export cmd ; eval $cmd ; unset cmd

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM