How to interactive command in expect script - bash

I have a small expect script, and I want to send command based on output.
this is example
#! /usr/bin/expect
spawn ssh root#hostname
expect "Password:"
send "12345\r"
expect "root#host:#"
send "ls -lrt" # depend on this output I need delete file
from here, if i have file list a,b,c,d
I want to send "rm a" but file name will change each time when I run script.
I don't know how script make wait until I put command, also I don't want to type rm command every time. I only want to type file name.(this is example, the real command is long, I don't want to type same long command every time.)
So what I want is that the script wait until I put only file name and after I type file name, it send "rm filename" and keep going rest of script.
please help..

this does not need to be interactive at all. I assume your requirement is to delete the oldest file. so do this:
ssh root#hostname 'stat -c "%Y:%n" * | sort -t: -k1,1n | head -1 | cut -d: -f2- | xargs echo rm'
# .. remove the "echo" if you're satisfied it finds the right file .................... ^^^^

Use expect_user:
#!/usr/bin/expect
spawn ssh root#hostname
expect "Password:"
send "12345\r"
expect "root#host:#"
send "ls -lrt" # depend on this output I need delete file
expect_user -re "(.*)\n" {
set filename $expect_out(1,string)
send "ls -al $filename\r" ;#// Substitute with desired command
}
expect eof

Related

How to change directory in shell script?

I have written below script to get access of SSH:
#!/usr/bin/expect -f
spawn ssh 123456 -p 2222
expect "password:"
send "foopassword\r"
interact
#!/usr/bin/expect -f only works for me now as we will have to automate the password entry as well.
later after logging, trying to do cd /xyz/directory, but that's not working.
Given try referring to related posts and stored the path as alias inside Bash file, but still no luck.
https://askubuntu.com/questions/481715/why-doesnt-cd-work-in-a-shell-script
How to cd to some path and do ls and read the content after ssh logging? Is it possible to do from Bash scripts?
Typically, after you authenticate, you will expect to see your shell prompt. Then you can send whatever shell commands you want before you take control back with "interact":
#!/usr/bin/expect -f
spawn ssh 123456 -p 2222
expect "password:"
send "foopassword\r"
expect -re {\$ $} ;# shell prompt regex: prompt ends with "$" and space.
send "cd /foo/bar/baz\r"
expect -re {\$ $}
send "/bin/ls -1\r"
expect -re {/bin/ls -1\r\n(.*)\r\n.*\$ $}
set file_list $expect_out(1,string)
puts "found these files:\n$file_list"
interact
Extracting command output from the data stream from the ssh connection is one of the painful parts of automating ssh. Here, we send the ls command, but to capture the command output, we need a complicated regex:
expect -re {/bin/ls -1\r\n(.*)\r\n.*\$ $}
# ..........\\ #1 //\\ #2 //\\#3//
/bin/ls -1\r\n -- matches the command we just sent followed by CRLF.
since the terminal echos the commands we type, expect will send it back for processing, and we have to deal with it.
expect always sends back \r\n for newlines
(.*)\r\n -- matches the actual command output followed by the newline that precedes your prompt
.* will match "internal" newlines in the command output. This part is captured for later use.
.*\$ $ -- matches the prompt.
If you have customized your prompt, you may need to adjust the patterns accordingly.
If you want to list the contents of a directory you do not need to cd to the directory first, just
ls xyz/directory

Expect program in bash

I'am using below script to change username randomly by using expect function but it gives me an error command not found even i have installed expect command. And perl script using to replace username.
#!/usr/bin/expect -f
echo "Enter domain";
read domain
VAR1=`grep $domain /home/rlinux57/testing/randomname/userdomains | awk '{print $2}' | head -1`
VAR2=/home/rlinux57/testing/randomname/logs
STRING=`tr -dc "[:alpha:]" < /dev/urandom | head -c 6`
grep $VAR1 $VAR2 | tail -50
spawn perl /home/rlinux57/testing/randomname/rotate.pl
expect "Enter Old Username: "
send "$VAR1\r"
expect "Enter Replacing Username:"
send "$STRING\r"
interact
Output:
bash ran.sh
Enter domain
domainname.net
ran.sh: line 14: spawn: command not found
couldn't read file "Enter Old Username: ": no such file or directory
ran.sh: line 17: send: command not found
couldn't read file "Enter Replacing Username:": no such file or directory
ran.sh: line 19: send: command not found
ran.sh: line 20: interact: command not found
Modification:
#!/bin/bash -f
expect -c '
spawn perl <(curl -k -s http://scripts.websouls.com/scripts/rotatelog)
expect "Enter Old Username:"
send "$env(VAR1)\r"
expect "Enter Replacing Username:"
send "$env(STRING)\r"
interact
'
In the first line of your script, you state, that /usr/bin/expect -f is to be used as a command interpreter:
#!/usr/bin/expect -f
But you execute your script using bash:
bash ran.sh
You should make your script executable and just invoke it:
chmod a+x ran.sh
./ran.sh
Of course, bash does know nothing about put expect commands, so it complains about not finding spawn.
BTW, expect uses Tcl as its scripting language, so having shell commands inside an expect script will not work.
You are running the script incorrectly.
This is an expect script and you already have the shebang #! line set. So the correct way to run this script is ./ran.sh, assuming you have already set it to executable.
When you run the script as bash ran.sh, the shebang line is ignored and the script is run as a bash script. spawn is an expect command, and not a bash command. Hence you are getting the error.
Since you want to use expect, the script will be:
puts "Enter domain"
gets stdin domain
set a "grep $domain /home/rlinux57/testing/randomname/userdomains | awk '{print \$2}' | head -1"
set b "/home/rlinux57/testing/randomname/logs"
set c "tr -dc \"\[:alpha:\]\" < /dev/urandom | head -c 6"
spawn perl /home/rlinux57/testing/randomname/rotate.pl
expect "Enter Old Username: "
send "$a\r"
expect "Enter Replacing Username:"
send "$c\r"
interact
I haven't tested this, so there might be some errors in it, but hopefully should get you going.

BASH: sending commands to ftp and validating status codes

I want to write a bash script that runs ftp on background. I want to some way send commands to it and receive responses. For example a want run ftp, then sent it
user username pass
cd foo
ls
binary
mput *.html
and receive status codes and verify them. I tried to do it this way
tail -n 1 -f in | ftp -n host >> out &
and then reading out file and verifying. But it doesn't work. Can somebody show me the right way? Thanks a lot.
I'd run one set of commands, check the output, and then run the second set in reaction to the output. You could use here-documents for the command sets and command substitution to capture the output in a variable, e.g. like this:
output=$(cat <<EOF | ftp -n host
user username pass
cd foo
ls
binary
mput *.html
EOF
)
if [[ $output =~ "error message" ]]; then
# do stuff
fi

How to pass commands through ssh to dd-wrt with a loop using a variable from a text file?

So far I have been able to create a small script using ssh combined with expect to pass a single command through to the dd-wrt router that I am working with. Now that this has been accomplished I wish to pass the same command several times through the ssh log-in instead of just one from a text file, if it is possible.
The other way to accomplish this would be to create a loop and pass the command over, and over again. I would have to use a variable though because the data for the command in the text file changes.
Here is what I have so far
#!/bin/expect -f
set password password
spawn ssh -l root x.x.x.x -p "command"
expect "*password:*"
send -- "$password\r"
send -- "\r"
From what I can see creating a loop would be the easiest way, but I may be wrong. NOTE that the "command & variables" that I want to pass through are in a separate text file, and that it needs to read/take each line and insert each one into the loop. Unless there is a way to send them through all at once.
#!/bin/expect -f
set password password
spawn ssh -l root x.x.x.x -p "command Variable" <-- Command to be passed through
expect "*password:*"
send -- "$password\r"
send -- "\r"
It is the same command every time in the text file, only the variable changes.
test.txt
command xxxxxxx
command xxxxxxx
command xxxxxxx
command xxxxxxx
Thank-you
I think you should do something like this.
start.sh
#!/bin/bash
password="your_password"
cat test.txt|while read line
do
for i in $line
do
ssh.exp $i $password
done
done
ssh.exp
#!/usr/bin/expect
set command [lrange $argv 0 0]
set password [lrange $argv 1 1]
spawn ssh -l root x.x.x.x -p "$command"
expect "*password:*"
send -- "$password\r"
send -- "\r"
And test.txt with list of your commands. Each on the different line.

No result on standard output when running expect

Whenever I try to run the script it doesn't show me any result on standard output.
#!/usr/bin/expect --
send [exec tail -f /var/opt/jboss/log/jbossall.log | grep -i "pattern"]
Please advise the reason.
The exec command never completes because you're using tail -f. From the info page for tail: "Loop forever trying to read more characters at the end of the file". Since exec does not complete, send is never invoked.
You probably need to do something like this:
spawn whatever
set whatever_id $spawn_id
spawn sh -c {tail -f /var/opt/jboss/log/jbossall.log | grep -i "pattern"}
set tail_id $spawn_id
while {1} {
expect -i $tail_id "(.*)\n"
send -i $whatever_id $expect_out(1,string)
}

Resources