获取一行用户输入,然后将其作为 Bash 命令执行
Get one line of user input and then execute it as Bash commands
我写了一个 expect 脚本来帮助在远程机器上执行命令。当执行完成后,我想获取一行用户输入,然后发送到远程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"
但是,如果输入类似于:ls /"
,我的程序将被阻止,因为远程 shell 期望通过提示字符串“>”获得更多字符。实际上,我希望 bash 不会提示更多输入,而不仅仅是打印错误消息:
$ read COMMAND
ls /"
$ eval "$COMMAND"
bash: unexpected EOF while looking for matching `"'
bash: syntax error: unexpected end of file
我可以在我的脚本中实现这个吗?
#!/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'?
如果我使用反引号或单引号来转义命令,那么如果用户在命令本身中使用反引号或单引号,那么它可能会失败。所以,为了克服这个问题,我在此处添加了文档。
输出:
dinesh@MyPC:~/Whosebug$ ./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:~/Whosebug$
更新:
使用here-doc
的主要原因是它使读取成为非阻塞命令。即我们可以快速执行下一个命令。否则,我们必须等到 Expect
超时。 (当然,我们可以动态更改超时值。)
这只是其中一种方法。您可以根据需要更改它,只需使用 read
命令即可。
我认为这对 interact
来说是一个很好的案例——让 expect 退到一边,让用户直接与生成的程序交互。
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
我写了一个 expect 脚本来帮助在远程机器上执行命令。当执行完成后,我想获取一行用户输入,然后发送到远程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"
但是,如果输入类似于:ls /"
,我的程序将被阻止,因为远程 shell 期望通过提示字符串“>”获得更多字符。实际上,我希望 bash 不会提示更多输入,而不仅仅是打印错误消息:
$ read COMMAND
ls /"
$ eval "$COMMAND"
bash: unexpected EOF while looking for matching `"'
bash: syntax error: unexpected end of file
我可以在我的脚本中实现这个吗?
#!/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'?
如果我使用反引号或单引号来转义命令,那么如果用户在命令本身中使用反引号或单引号,那么它可能会失败。所以,为了克服这个问题,我在此处添加了文档。
输出:
dinesh@MyPC:~/Whosebug$ ./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:~/Whosebug$
更新:
使用here-doc
的主要原因是它使读取成为非阻塞命令。即我们可以快速执行下一个命令。否则,我们必须等到 Expect
超时。 (当然,我们可以动态更改超时值。)
这只是其中一种方法。您可以根据需要更改它,只需使用 read
命令即可。
我认为这对 interact
来说是一个很好的案例——让 expect 退到一边,让用户直接与生成的程序交互。
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