Regular expressions in expect and shell script - regex

Friends , im trying to automate a routing using expect , basically its a debug plugin in a special equipment that i need to log some data , to access this debug plugin my company needs to give me a responsekey based on a challengekey , its a lot of hosts and i need to deliver this by friday , what i've done so far.
#!/usr/bin/expect -f
match_max 10000
set f [open "cimc.txt"]
set hosts [split [read $f] "\n"]
close $f
foreach host $hosts {
spawn ssh ucs-local\\marcos#10.2.8.2
expect "Password: "
send "Temp1234\r"
expect "# "
send "connect cimc $host\r"
expect "# "
send "load debug plugin\r"
expect "ResponseKey#>"
sleep 2
set buffer $expect_out(buffer)
set fid [open output.txt w]
puts $fid $buffer
close $fid
sleep 10
spawn ./find-chag.sh
sleep 2
set b [open "key.txt"]
set challenge [read $b]
close $b
spawn ./find-rep.sh $challenge
sleep 3
set c [open "rep.txt"]
set response [read $c]
close $c
puts Response-IS
send "\r"
expect "ResponseKey#> "
send "$response"
}
$ cat find-chag.sh
cat output.txt | awk 'match($0,"ChallengeKey"){print substr($0,RSTART+15,38)}' > key.txt
$ cat find-rep.sh
curl bla-blabla.com/CIMC-key/generate?key=$1 | grep ResponseAuth | awk 'match($0,"</td><td>"){print substr($0,RSTART+9,35)}' > rep.txt
i dont know how to work with regexp on expect so i put the buffer output to a file and used bash script , the problem is that after i run the scripts with spawn looks like my ssh session is lost , does anyone have any tips? should i use something else instead of spawn to invoke my scripts?

expect -re "my tcl compatible regular expression goes here"
Should allow you to use regular expressions.

Related

Expect Script to match on multi-line response

I am receiving the response to a Unix cat /etc/hosts and would like to match on this data with Expect - so I can write it local disk.
I have
#!/usr/bin/expect -f
set timeout -1
spawn nc -lvnp 9090
match_max 100000
expect -re {.*(Connection received).*}
puts "Getting hosts file"
send -- "cat /etc/hosts\r"
expect -re "(.*)\n"
The host file is multiple lines and I am unable to construct the correct regular expression to match on it.
Help would be gratefully received
Update
When interact with when the remote service via netcat manually the response interaction looks like this :
nc -lvnp 9090 Listening on 0.0.0.0 9090 Connection received on
192.168.236.135 44686 cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 ubuntu
# The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters
my Expect code is :
#!/usr/bin/expect -f
set timeout -1
spawn nc -lvnp 9090
match_max 100000
expect -re {.*(Connection received).*}
puts "******Getting hosts file*******"
log_user 0
send -- "cat /etc/hosts \r"
expect -re "(.*\[\r\n])+"
#expect -re "(.*\[\r|\n]).*"
#expect -re "(.*\[\t|\r|\n]).*"
expect -re "(.*\[\r\n]).*$"
puts "Output 0 string"
puts <<<<$expect_out(0,string)>>>>
puts ""
puts "Output 1 string"
puts <<<<$expect_out(1,string)>>>>
puts ""
puts "Output buffer"
puts <<<<$expect_out(buffer)>>>>
puts ""
puts [open hosts.txt w] $expect_out(buffer)
send -- "\x03"
Just seem to be unable to match on the whole response - I'm not 100% sure if I need to match on EOF or EOL or something else. The newlines and tab are also part of the problem I think.
I basically just to to capture the whole response from the 'send -- "cat /etc/hosts" and write that to disk
turns out he response from the remote server was too quick.
A simple 'sleep 1' was good enough to slow things down
#!/usr/bin/expect -f
set timeout -1
spawn nc -lvnp 9090
match_max 100000
expect -re {.*(Connection received).*}
puts "Getting hosts file"
send -- "cat /etc/hosts\r"
sleep 1
expect -re "(.*)\n"

Why doesn't this program copy all my files, using scp?

I wrote a little program which, in first case, slices a list of files and directory names so I get a list of files and a list of directories.
#!/usr/bin/expect -f
set mdproot "****"
set mySource "****"
set myDest "****"
set myDirs {}
set myFiles {}
set i 1
set y 0
lappend myDirs [lindex $argv 0]
foreach variable $argv {
lappend myDirs [lindex $argv $i+1]
lappend myFiles [lindex $argv $y+1]
incr y
incr y
incr i
incr i
}
set DIRECTORIES [lsearch -all -inline -not -exact $myDirs {}]
set FILES [lsearch -all -inline -not -exact $myFiles {}]
#puts " "
#puts $DIRECTORIES
#puts " "
#puts $FILES
foreach file $FILES dir $DIRECTORIES {
puts " Fichier : $file et repertoire : $dir"
spawn scp -p "$mySource/$file" "$myDest/$dir"
expect -re "(.*)assword: " {sleep 1; send -- "$mdproot\r" }
expect eof { return}
}
There are my lists:
$argv :
2017-11-30
2017-11-30_15-10-44_P_8294418.33_Q1
2017-11-30
2017-11-30_15-10-44_R_8294418.33_Q1
2018-03-07
2018-03-07_09-30-57_R_HOURS_Q1
2018-04-13
2018-04-13_13-23-25_R_HOURS_Q1
2018-05-02
2018-05-02_11-19-37_R_HOURS_Q1
2018-03-07
2018-3-7_9-30-57_P_HOURS_Q1
2018-04-13
2018-4-13_13-23-25_P_HOURS_Q1
2018-05-02
2018-5-2_11-19-37_P_HOURS_Q1
$DIRECTORIES :
2017-11-30
2017-11-30
2018-03-07
2018-04-13
2018-05-02
2018-03-07
2018-04-13
2018-05-02
$FILES :
2017-11-30_15-10-44_P_8294418.33_Q1
2017-11-30_15-10-44_R_8294418.33_Q1
2018-03-07_09-30-57_R_HOURS_Q1
2018-04-13_13-23-25_R_HOURS_Q1
2018-05-02_11-19-37_R_HOURS_Q1
2018-3-7_9-30-57_P_HOURS_Q1
2018-4-13_13-23-25_P_HOURS_Q1
2018-5-2_11-19-37_P_HOURS_Q1
Actually I have 2 problems (3 in the case we count how trash this code is).
First, when I run my program, I have my % indicator for each file I am copying and except the last one, they all stop before they get to 100%.
Then, I can see that the scp command isn't done on all the files, the program stops pretty much every time at the 4th file.
root#raspberrypi:~# ./recupFileName.sh
spawn scp -p /root/muonic_data/2017-11-30_15-10-44_P_8294418.33_Q1 marpic#192.168.110.90:/home/marpic/muonic_data/Data_Q1/2017-11-30
marpic#192.168.110.90's password:
2017-11-30_15-10-44_P_8294418.33_Q1 15% 68MB 6.9MB/s 00:53
spawn scp -p /root/muonic_data/2017-11-30_15-10-44_R_8294418.33_Q1 marpic#192.168.110.90:/home/marpic/muonic_data/Data_Q1/2017-11-30
marpic#192.168.110.90's password:
2017-11-30_15-10-44_R_8294418.33_Q1 41% 69MB 8.5MB/s 00:11
spawn scp -p /root/muonic_data/2018-03-07_09-30-57_R_HOURS_Q1 marpic#192.168.110.90:/home/marpic/muonic_data/Data_Q1/2018-03-07
marpic#192.168.110.90's password:
2018-03-07_09-30-57_R_HOURS_Q1 82% 51MB 7.2MB/s 00:01
spawn scp -p /root/muonic_data/2018-04-13_13-23-25_R_HOURS_Q1 marpic#192.168.110.90:/home/marpic/muonic_data/Data_Q1/2018-04-13
marpic#192.168.110.90's password:
2018-04-13_13-23-25_R_HOURS_Q1 100% 6940KB 6.8MB/s 00:01
As you can see, there should be 8 files copied with 100% accuracy, but there are no error messages so I don't know where to start my research.
EDIT :
I added the "set timeout -1" in my script, but now the script is copying only my first file with 100% accuracy, then stops. Any answers ?
root#raspberrypi:~# ./recupFileName.sh
Fichier : 2017-11-30_15-10-44_P_8294418.33_Q1 et repertoire : 2017-11-30
spawn scp -p /root/muonic_data/2017-11-30_15-10-44_P_8294418.33_Q1 marpic#192.168.110.90:/home/marpic/muonic_data/Data_Q1/2017-11-30
marpic#192.168.110.90's password:
2017-11-30_15-10-44_P_8294418.33_Q1 100% 437MB 7.5MB/s 00:58
root#raspberrypi:~#
The problem should be in expect eof. By default the timeout is 10 seconds so expect eof would return after 10 seconds though the scp is still running.
You can use a larger timeout.
Option #1:
# set the default `timeout'
set timeout 3600 ; # or -1 for no timeout
Option #2:
expect -timeout 3600 eof
Note that your
expect eof { return }
would exit the whole script so the foreach loop runs for only once, you need just
expect eof

using TCL command line, is there a way to stop showing characters?

I'm building a tool were a command with a password needs to be entered.
I want when I enter this command with the password, the command line replaces each character with "*" or " ", so the command and the password will not be observable !
is there such a command that tells the TCL interpreter "from this point, show each character entered as *", and then switch back to regular mode ?
any other suggestion will be valuable too.
In your case, you shall take "full control" over your terminal and disable its default echoing behavior (In UNIX the likes the terminal should be entered into the so-called raw mode)
Then, you can read the characters one-by-one (till max password size or till Enter is pressed) and echo '*' per each pressed character.
You got working code examples both on UNIX and Windows how doing so here
You may want reading also this link echo-free password entry TCL wiki
proc enableRaw {{channel stdin}} {
exec /bin/stty raw -echo <#$channel
}
proc disableRaw {{channel stdin}} {
exec /bin/stty -raw echo <#$channel
}
enableRaw
set c [read stdin 1]
puts -nonewline $c
disableRaw
package require twapi
proc enableRaw {{channel stdin}} {
set console_handle [twapi::GetStdHandle -10]
set oldmode [twapi::GetConsoleMode $console_handle]
set newmode [expr {$oldmode & ~6}] ;# Turn off the echo and line-editing bits
twapi::SetConsoleMode $console_handle $newmode
}
proc disableRaw {{channel stdin}} {
set console_handle [twapi::GetStdHandle -10]
set oldmode [twapi::GetConsoleMode $console_handle]
set newmode [expr {$oldmode | 6}] ;# Turn on the echo and line-editing bits
twapi::SetConsoleMode $console_handle $newmode
}
enableRaw
set c [read stdin 1]
puts -nonewline $c
disableRaw
(Assuming Linux.) By far the easiest way to handle passwords in a terminal is to turn off echoing of input but leave the terminal otherwise in cooked mode. It won't show a * for each entered character, but it does mean that you don't have to handle things like backspace (when a user realises they typed the last couple of characters wrong before hitting Return), etc.
exec /bin/stty -echo <#stdin
set password [gets stdin]
puts ""
exec /bin/stty echo <#stdin
If you've got Tcl 8.6, you can easily make this more robust with this procedure:
proc getPassword {{prompt "Password: "}} {
exec /bin/stty -echo <#stdin
try {
puts -nonewline $prompt
flush stdout
return [gets stdin]
} finally {
puts ""
flush stdout
exec /bin/stty echo <#stdin
}
}
(It's possible to use catch and some scripting to emulate try…finally but it's really annoying.)
If you have a GUI and prefer that, you make a password entry box by setting the -show option to something non-empty (e.g., * to show an asterisk).

Using regular expressions with expect

What I'm trying to do is write an expect script that will allow me to search for file A, and if file A is found then send a series of commands. If files B, or C are found then continue on through the script. I keep getting stuck on the regular expression. I run the expression through www.myregextester.com alone with the data I'm searching for and it matches up just fine. If anyone has any experience with this I would really appreciate the help.
send "term length 0\r"
expect "*#"
send "wr mem\r"
expect "*#"
send "dir flash:\r"
expect
if [[ \bc3750-ipservicesk9-mz.122-55.SE7.bin\b ]]; then {
send "conf t\r"
expect "*(config)#"
send "boot system flash:c3750-ipservicesk9-mz.122-55.SE7.bin\r"
expect "*(config)#"
send "exit\r"
expect "*#"
send "reload at 02:00 8 June\r"
expect "System configuration has been modified. Save? [yes/no]:"
send "yes\r"
expect "Proceed with reload? [confirm]"
send "\r"
expect "*#"
send "wr\r"
expect "*#"
send "exit\r
expect eof
elif [[ \bc3750-ipservicesk9-mz.122-55.SE5\b | b\c3750-ipservicesk9-mz.122-55.SE5.bin\b} ]]; then
fi
}
expect {
-re {\mc3750-ipservicesk9-mz\.122-55\.SE7\.bin\M} {
send "conf t\r"
#...
}
-re {\mc3750-ipservicesk9-mz\.122-55\.SE5(?:\.bin)?\M}
}
Expect is an extension of Tcl: you can read about Tcl regular expressions here.

sos Job scheduler

i am using sos job scheduler which support many language.i accept the shell script to write jobs but i am not a shell script writer.i want to implement a following points in job scheduler:
execute a shell script A. script A return "success" if time is between 6:00AM and 3PM.else it return "fail".
on "success" execute a shell script C or on "Fail" it execute shell script B.
Script B and Script C send email with“Success” or “Failure” in subject line.
please help me to sortout the above discuss problem.
Thanks
There are two command line utilities that are helpful in this case:
date: Displays the current time/date in a specified format.
mail: Sends e-mail from the command line.
Since we only need the full hour for our logic I use the date format "+%H" (hour from 0-23). This gives the following script basis:
#!/bin/sh
hour=$(date +%H)
if [ $hour -gt 6 -a $hour -lt 15 ]; then
echo "message body" | mail -s Success <your e-mail address>
else
echo "message body" | mail -s Failure <your e-mail address>
fi
#!/bin/bash
hour=$(date +%H)
recipient="root"
case "$hour" in
[6-9]|1[0-5])
subject="success"
body="message"
;;
*)
subject="failure"
body="message"
;;
esac
echo $body | mailx -s "$subject" "$recipient"