The expect script returning invalid command while I trying to create a folder after login to server via ssh
This is the below error I got
invalid command name "mkdir"
while executing
"mkdir new"
(file "./connecttotravalour.exp" line 8)
And the code on my expect script is :
#!/bin/bash
#connect to travalour host
spawn ssh travalour#travalour.local
expect "password"
send "P#ssw0rd\r"
interact
mkdir new
Posting an answer form askubuntu for similar question
The main thrust of expect programming is send and expect pairs: you send some text to the spawned process and expect a response. In this case, you send the mkdir command, and expect to see your prompt to know that the command has completed. Prompts are best matched as regular expressions to match the end of it. Since prompts are so configurable, you might want to edit the prompt expression: this one matches a literal dollar sign and a space at the end of the string.
#!/bin/bash
#connect to travalour host
spawn ssh travalour#travalour.local
expect "password"
send "P#ssw0rd\r"
set prompt_re {\$ $}
expect -re $prompt_re
send "mkdir -p new"
expect -re $prompt_re
interact
Related
Im embedding an expect script inside of a bash script in order to place some ftp files on a server.
Im trying to have the expect script return an output value of success or failure to the bash process so I can act on it, but I am failing miserably.
The script looks like this:
sftper()
{
local filename="$1"
local user="user"
local password="password"
local host="ftpserver"
local in=1
IFS= read -r -d '' expect_commands <<EOD >echo_log
spawn /usr/bin/sftp $user#$host
expect "*assword:"
send "$password\r"
expect "sftp>"
send "put $filename\r"
expect "sftp>"
send "bye\r"
interact
EOD
expect -c "${expect_commands//
/;}"
in="$?"
return "$in"
}
`
Please, what am I doing wrong, and how can I fix this?
The single most surprising thing in your script is that you call interact, which is an Expect command to allow the user to be connected directly to the spawned program. However, it's unlikely to be useful after you have sent a bye command to sftp; a close; exit sequence would be much more expected (to shut down the controlling virtual terminal and quit the Expect script).
Thus, I'd expect something more like:
IFS= read -r -d '' expect_commands <<EOD >echo_log
spawn /usr/bin/sftp $user#$host
expect "*assword:"
send "$password\r"
expect "sftp>"
send "put $filename\r"
expect "sftp>"
send "bye\r"
close
exit
EOD
More generally, you ought to think about what happens if a problem occurs (e.g., if the password has been expired), and it is probably easier to write a full expect script instead of running the gauntlet of all that shell quoting. I've added a few small explanatory comments…
# Assuming this is in a file called do_sftp_put.exp
# set up the variables; first line is how to get a command line argument
set filename [lindex $argv 0]
set user "user"
set password "password"
set host "ftpserver"
# launch sftp
spawn /usr/bin/sftp $user#$host
# login sequence
expect "*assword:"
send "$password\r"
expect "sftp>"
# send the file
send "put $filename\r"
expect "sftp>"
# Shut down
send "bye\r"
close
exit
Then your shell script wrapper becomes much simpler:
sftper()
{
expect /path/to/do_sftp_put.exp "$1"
return $?
}
Not much fancy quoting is required here; this is how everything is designed to work. Yes, the expect script needs careful protection so that only you can read it as it contains live credentials, but you had that problem before in your shell code so that's nothing new.
[EDIT]: Of course, this still doesn't detect errors. For that, you need a more complex script. One of the most common errors is for the password to be wrong (or to not match the user). To solve that one, we take this bit:
# login sequence
expect "*assword:"
send "$password\r"
expect "sftp>"
and upgrade it to something like:
# login sequence
expect "*assword:"
send "$password\r"
expect {
"password" {
# It's asking for the password *again*; must be wrong!
# Kill the sftp program and exit with an error code
close
exit 1
}
"sftp>"
}
Working out how to detect an error isn't always trivial (you can use regular expressions and so on, and you need to understand exactly what you are working against), and in some cases it's actually better to back up and try another approach entirely. For sftp specifically, I would be trying to get an SSH identity configured so that I could use key-based auth instead of password-based auth, as that's significantly more secure in practice in several ways. However, that's a substantial change to your operations so it is definitely out of the scope of the question.
Is there a way to execute a "read" command from a spawned ssh subprocess through expect? When I try the below code, read doesn't recognize end of input through "ENTER" key (it just goes to next line). I tried other "read" options (e.g. limiting number of characters, timeout, etc.) but they do not work. I know there are ways to get user input within Expect script itself but I need the input to be received through a bash command.
function foo() {
expect <<EOF
set timeout -1
spawn ssh -t $1
expect "]"
send "read x\r"
expect "]"
send "echo $x\r"
expect "]"
send "exit\r"
expect eof
EOF
}
I'm trying to execute commands remotely over ssh using an expect script that will log in with a password. So far I have the following script (details changed of course):
#!/usr/bin/expect
spawn ssh user1#cpu3.lab.ie
expect "password:"
send "psw123\r"
expect "$"
send "mkdir pswdtest\r"
I name this script testpswd.sh and then runchmod +x testpswd.sh, d2u testpswd.sh and ./testpswd.sh.
Apparently the script manages to login because I get the Last login:... prompt. However, after this the script seems to wait for a bit and then exit back out of ssh, without making a directory called pswdtest (as I can check afterwards).
I have tried looking up tutorials etc and changing the script above in all ways I could think of, e.g. expect "user1#cpu3:~$"instead of expect "$" and so on.
I'm running windows and use cygwin (hence the d2u), and the network I'm logging into uses Linux.
Any ideas?
While developing an expect script, always add exp_internal 1 at the top of the script: expect will show you what it's matching (or not).
Perhaps you could match the prompt with this: expect -re {\$\s*$}
After you send something, you should expect something
exp_internal 1
set prompt {\$\s*$}
spawn ssh user1#cpu3.lab.ie
expect "password:"
send "psw123\r"
expect -re $prompt
send "mkdir pswdtest\r"
expect -re $prompt
send "exit\r"
expect eof
In the below code (which will run on my linux machine), I am trying to copy run_check_node.sh to two different remote linux machine and then executing that script from my machine only.
Issue: The run_check_node.sh script takes around 25 minutes to execute. But the run_check_node.sh script execution on the remote linux machine stops after around 3-4 minutes and then next iteration of for loop is taken. Same thing happen in this next iteration also. I tried using set timeout 1200, to account for those 25 min, but still same issue. Can anyone please help what to do?
Question: The machine IPs I am using, sometimes they ask for password and sometimes don't. So, I am expecting for it. So, in case no password is asked, it simply throws some message on console and below script execution continues. Please tell if this is correct way of handling of whether password will be asked or not?
#!/bin/bash
Linux1_ip=10.20.30.40
Linux2_ip=10.100.20.30
pass="Gaur"
IP=("$Linux1_ip" "$Linux2_ip")
home="/post_checks"
############################ Linux_ip CHECKS ####################################
for ne in "${IP[#]}"
do
expect -c "
spawn ssh root#$ne \"mkdir /post_checks_$ne\"
expect yes/no { send yes\r; exp_continue }
expect password { send $pass\r; exp_continue }
exit
"
expect -c "
spawn scp $home/run_check_node.sh root#$ne:/post_checks_$ne/
expect yes/no { send yes\r; exp_continue }
expect password { send $pass\r; exp_continue }
exit
"
expect -c "
spawn ssh root#$ne \"chmod +x /post_checks_$ne/run_check_node.sh; bash /post_checks_$ne/run_check_node.sh\"
expect yes/no { send yes\r; exp_continue }
expect password { send $pass\r; exp_continue }
exit
"
fi
done
Now, this may not explain why you're seeing what you're seeing, but it may be a useful workaround.
How about you try to execute your run_check_node.sh shell script on the remote in the background? You would then disconnect and let it complete on its own.
So, basically, your 3rd spawn line would be:
spawn ssh root#$ne \"chmod +x /post_checks_$ne/run_check_node.sh; bash /post_checks_$ne/run_check_node.sh &\"
If you needed to check on completion of the shell script, what I'm proposing would not be acceptable... but I don't see your Bash script doing any checking on that, so I'm thinking it may work for you.
Try it out and let me know how it goes.
I just got some help in automating my password input during an SFTP connection by using Expect.
I then tried to issue a put command and things got complicated again. I'm using the following code:
#!/usr/bin/expect
#!/bin/sh
expect -c "
spawn sftp remoteuser#*.*.*.*
expect \"remoteuser#*.*.*.*'s password:\"
send \"passwrd\r\"
interact "
echo "put output/data.xml\r"
echo "quit\r"
My password input and connection to the remote server works just fine but I am struggling to get the put output/data.xml command to display and execute at the SFTP prompt.
My echo "put output/data.xml\r" and echo "quit\r" lines just print as text which is not entirely surprising but I really don't know what else might work.
I understand you need some help, but you should at least try doing some reading. When you say expect -c 'some stuff ...', you are specifying the entire expect script as the parameter to the -c option. The Expect session will not exist afterward.
Also, try to understand what the interact command does instead of blindly applying what someone advises.
Anyway, the solution:
expect <<'END_EXPECT'
set timeout -1
spawn sftp remoteuser#1.2.3.4
expect "[Pp]assword:"
send "passwrd\r"
expect "whatever the sftp prompt looks like"
send "put output/data.xml\r"
expect "whatever the sftp prompt looks like"
send "quit\r"
expect eof
END_EXPECT
Note that the here-doc delimiter is quoted when you first see it. That way, you will not be subjected to any shell expansions. It's like the entire here-doc is single-quoted.