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:
#! /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:
$ 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 ?
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.
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. i.e. We can proceed quickly with next command. Else, we have to wait till the timeout of 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.