how to use expect inside shell script - shell

I have a bash+expect script which has to connect normal user, i want
to read the specific file and store into the variable to be used
after while that specific file in root user. How can i get the value ?
My script is:
#!/bin/bash
set prompt ">>> "
set command ls /root/test1
expect << EOF
spawn su root
expect "password:"
send "rootroot\r"
expect "$prompt\r"
send "$command\r"
expect "$prompt\r"
expect -re "(.*)\r\n$prompt\r\n"
EOF
echo "$command"
if [ ! -f "$command" ]; then
echo "file is not exist"
else
echo "file is exist"
fi
whenever i'm execute my shell script it show following output:
ls: /root/: Permission denied
file is not exist
basically test is there but it is showing "file is not exist"

This question is very old but i hope someone gets help from this answer.
--> You should use #!/usr/bin/expect or #!/bin/expect to use expect properly, expect<<EOF might work but thats not conventional way to write script.
--> You script should end with EOF statement . Ex.
#!/usr/bin/expect << EOF
<some stuff you want to do>
EOF
--> Some basic thing about spawn. Whatever you write in spawn will execute but it will not have effect on entire script. Its not like environment variables.
In short, spawn will start new process and your command is not under spawn process.
Ex.
#!/usr/bin/expect
spawn bash -c "su root '<your-cmd-as-root>'"
<some-expect-send-stuff-etc>
Now in your script, $command should be write inside spawn like i showed in above example.

Related

Trying to Create a remote login tool: "interact" in "expect << EOF" does not work

The use case of this script is I have various servers with different ssh keys. I am trying to write a script so when called will log into the specified server. An example of usage would be:
./ServerLogin.sh Server1
I feel that I am fairly close, but The last part of expect interact is tripping me up. This is a simplified version:
#!/bin/bash
ServerName="$1"
case $ServerName in
"Server1") IP="1.2.3.4" ; keyPath="/path/to/key.pem" ; password="password" ; break ;;
*) echo "Server not recognized" ; exit ;;
esac
/usr/bin/expect << EOD
spawn ssh -i $keyPath user#$IP
expect "*.pem': "
send "$password\r"
interact
EOD
The result of this is it logs in and immediately closes. I want for the session to remain interactable.
Any ideas?
The problem is in expect << EOF. With expect << EOF, expect's stdin is the here-doc rather than a tty. But the interact command only works when expect's stdin is a tty. Your answer is one solution. Another solution is to use expect -c if you prefer not using a tmp file.
expect -c "
spawn ssh -i $keyPath user#$IP
expect \"*.pem': \"
send \"$password\r\"
interact
"
After toying around with it some more, I found a working solution. Basically create the expect script and run it. Why it works like this and not in the original question is beyond me. But it works and I will use this for the time being. Thanks everyone for the help!
Working Solution:
#!/bin/bash
ServerName="$1"
case $ServerName in
"Server1") IP="1.2.3.4" ; keyPath="/path/to/key.pem" ; password="password" ; break ;;
*) echo "Server not recognized" ; exit ;;
esac
function WriteExp {
echo "#!/usr/bin/expect"
echo "spawn ssh -i $keyPath ubuntu#$IP"
echo "expect \"*.pem': \""
echo "send \"$password\\r\""
echo "interact"
}
WriteExp > $ServerName.exp
chmod 755 $ServerName.exp
/usr/bin/expect $ServerName.exp
# Cleanup the evidence
rm $ServerName.exp
Using just tcl/expect, instead of a hybrid of shell and it, makes for much cleaner code, without any of the potential issues posed by shell variable interpolation:
#!/usr/bin/expect -f
switch -- [lindex $argv 0] {
Server1 {
set IP 1.2.3.4
set keyPath /path/to/key.pem
set password "password"
}
default {
puts stderr "Server not recognized"
exit 1
}
}
spawn ssh -i $keyPath user#$IP
expect "*.pem': "
send "$password\r"
interact

expect not taking ssh arguments while/for loop [duplicate]

I have list of filenames in a text file,need to transfer each file into server using scp command.I am reading filenames from Read.sh and passing each file name to transfer.sh script but scp is not executing command in this transfer script.If I run transfer.sh alone with passing args its working fine.
List.txt
/home/kittu/file1.txt
/home/kittu/file2.txt
/home/kittu/file3.txt
Read.sh
#!/bin/bash
while read p; do
echo $p
./transfer.sh "$p"
done <List.txt
transfer.sh
#!/usr/bin/expect -f
# get filename from command-line
set f [lindex $argv 0]
spawn scp "$f" user#192.168.4.151:/home/user/Desktop/
expect "password"
send "123\r"
interact
I just run Read.sh as
>./Read.sh
Output:
/home/user/Desktop/file1.txt
spawn scp /home/mbox140/Desktop/test.sh mbox140#192.168.4.151:/home/mbox140/Desktop/videos/
user#192.168.4.151's password:
Its not executing next statement.Please suggest me any solution.
Try the below script , The changes are that the Transfer.sh is wrapped into bash.sh.
and the reason it waits in the password may be because you are expecting a wrong pattern , try "Password" instead of "password" and after send command, expect for the terminal pattern so that the scp finishes
#!/bin/bash
while read p; do
echo $p
{
/usr/bin/expect << EOF
spawn scp $p user#192.168.4.151:/home/user/Desktop/
expect "Password"
send "123\r"
expect "*#*"
EOF
}
done <List.txt

How to use expect inside bash script [duplicate]

This question already has an answer here:
Embedding an Expect script inside a Bash script
(1 answer)
Closed 5 years ago.
Could anybody please tell me why this is not working?
#!/bin/bash
cd /home
touch somefile
/usr/bin/expect<<FILETRANSFER
spawn scp -r -P remoteServerPort somefile remoteServerIP:/home
expect "assword:"
send "MyPassWord\r"
interact
FILETRANSFER
echo "It's done"
It doesn't give any error but file is not transferred to remote server.I have tried many ways still couldn't find any solution.
The bash script you have defined is passing the expect commands on the standard input of expect. However, the expect command requires its arguments on a file or as an argument using the -c option.
You have several options but to add the less modifications on your script you just need to use the process substitution to create a here-document (temporary) for the expect command.
#!/bin/bash
echo "[DEBUG] INIT BASH"
cd /home
touch somefile
/usr/bin/expect <(cat << EOF
spawn scp -r -P remoteServerPort somefile remoteServerIP:/home
expect "Password:"
send "MyPassWord\r"
interact
EOF
)
echo "[DEBUG] END BASH"

Expect Script - bash script file not found

My expect script
#!/usr/bin/expect -f
#I tried replacing sh - with bash -s still no positive results
spawn ssh xxxx#yyyy "sh -" < test.sh
expect "password: "
send "zzzzz\r"
expect "$ "
This command works well if executed in the terminal
ssh xxxx#yyyy "sh -" < test.sh
But if I execute it via expect script; it fails.
This is the output if I execute it via the expect script. May I know where I am going wrong
bash: test.sh: No such file or directory
P.S : Yes, the file exists and the credentials are right.
Expect script was unable to read the contents of the file, that was the issue. Solved it by reading the contents of the file and passing that variable instead of the file name,
set fh [open test.sh r]
set contents [read $fh]
close $fh
and replacing the sh- with bash -c '$contents'
Thank you everyone for the valuable comments.

How can I execute all script parameters that use here doc?

I have a simple script, which I use throughout my code base, called sshpass.
#!/bin/bash
expect << EOF
spawn $#
expect {
"*assword" {
send "$SSHPASS\n"
}
}
expect eof
EOF
The way I'm currently utilizing this script is like this -
./sshpass scp archive.tgz $SERVER:$DIR
This works quite well when the SSH commands are one-liners. My issue is when I attempt to execute a command through sshpass that uses a here doc.
./sshpass ssh $user#$server /bin/bash << EOF
echo "do this..."
echo "do that..."
echo "and the other..."
EOF
The above fails because $# only parses out ssh $user#$server /bin/bash.
Please no comment with regards to how I'm handling my SSH authentication. When forced to use Cygwin there are specific things, such as key authentication and administrative privileges, that simply do not work.
The heredoc will replace stdin for your script. If you want it to be accessed as a parameter, use command substitution like
./sshpass ssh $user#$server /bin/bash $(cat << EOF
echo "do this..."
echo "do that..."
echo "and the other..."
EOF
)
although that probably won't end up doing exactly what you want, because it will be passing each word as it's own positional argument, so you will be running
ssh $user#$server echo "do this..." echo "do that..." echo "and the other..."
which will have the first echo get all the rest as arguments. You'll need semi colons at the end of each command, and to have quotes around the whole thing so you don't do some of it remotely and some of it locally. So I should have recommended it as:
./sshpass ssh $user#$server /bin/bash "$(cat << EOF
echo 'do this...';
echo 'do that...';
echo 'and the other...'
EOF
)"
but this still gives me an uneasy feeling as it's very likely easy to "do the wrong thing" with something like this

Resources