How can I remove special characteres from expect? - bash

So I'm using the next expect script in order to get the running-config of a switch and then save it to a file:
#!/usr/bin/expect
set timeout 9
set username [lindex "foo"]
set password [lindex "bar"]
set hostname [lindex "1.2.3.4"]
spawn ssh -q $username#$hostname
expect {
timeout { send_user "\nTimeout!\n"; exit 1 }
"*assword"
}
send "$password\n"
expect {
timeout { send_user "\nWrong password\n" ; exit 1 }
"switch-00>"
}
send "enable\n"
expect {
"switch-00#"
}
send "show running-config\n"
log_file -noappend log.txt
expect {
-ex "--More--" { send -- " "; exp_continue }
"*#" { log_file; send "exit\r" }
}
send "exit\n"
close
It works as it should except for this:
--More--^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H^H ^H
which is appearing in log.txt every time "--More--" gets printed.
It's not an issue to remove "--More--" later on using bash but if I do:
grep "^H" log.txt
there's no output, so I cannot remove it as it doesn't match.
I was trying to find a way to not output special characteres with expect if possible but didn't find any, so I'm asking here in case anyone knows.
A solution using bash would help me aswell but using expect is prefered.

You could use the bash tr utility. From the man page
NAME
tr -- translate characters
DESCRIPTION
The tr utility copies the standard input to the standard output with sub-
situation or deletion of selected characters.
SYNOPSIS
tr [-Ccsu] string1 string2
tr [-Ccu] -d string1
-C Complement the set of characters in string1, that is ``-C ab''
includes every character except for `a' and `b'.
-c Same as -C but complement the set of values in string1.
-d Delete characters in string1 from the input.
To Strip out non-printable characters from file1.
tr -cd "[:print:]\n" < file1 # This is all you need.

Related

expect script - how to split the output of a command into several variables

I am trying to set up a expect script that logs in to a remote server and
fetches the 3 last created logfiles. The output (1 line) looks like below:
root#server1:/cluster/storage/var/log/alarms$
Last 3 created files are: FmAlarmLog_20180515_1.log FmAlarmLog_20180516_2.log FmAlarmLog_20180517_3.log
How can I split this output and create 3 different variables (one for each logfile) from this output?
The name of the logfiles always starts with "FmAlarmLog_"
I need to add later the part handling the fetching of those files.
#!/usr/bin/expect -f
set passwd "xxx"
set cmd1 "ls -ltr | tail -3 | awk '{print \$NF}'"
set dir "/cluster/storage/var/log/alarms"
set timeout 1
set prompt1 "*\$ "
log_user 0
spawn ssh admin#10.30.35.36
expect {
-re ".*Are.*.*yes.*no.*" {
send "yes\n"
exp_continue
}
"*?assword:*" {
send $passwd
send "\n"
}
}
expect $prompt1 { send "cd $dir\r"}
expect $prompt1 { send "$cmd1\r"}
set Last3LogFiles {}
expect \n
expect {
-re {^([^\r\n]*)\r\n} {
lappend Last3LogFiles $expect_out(1,string)
exp_continue
}
-ex $prompt1
}
send_user "Last 3 created files are: $Last3LogFiles\n"
send "exit\n"
exit 0
Try this:
expect $prompt1
send "$cmd1\r"
# express the prompt as a regular expression.
# best practice is to match the prompt at the end of the current input,
# I don't know if you have a space at the end of your prompt
expect -re {(.*)\r\n\$ ?$}
# command output is in $expect_out(1,string)
set Last3LogFiles [regexp -inline -all {FmAlarmLog_\S+} $expect_out(1,string)]

Bash inconsistent escaping of asterisk * in expect?

I've got 2 expect commands, however, I don't understand the expansion that's going on. (In context, I have a script that connects to a server, downloads and blanks all the log files in a specified directory.)
expect -c "
set timeout 1
spawn scp user#hostname:/logdir/\*.log .
expect yes/no { send yes\n ; exp_continue }
expect password: { send $pass\n }
expect 100%
sleep 1
exit
";
In this command, expect displays the spawned command as spawn scp user#hostname:/logdir/*.log . Which means that the \ was removed.
expect -c "
set timeout 1
spawn ssh user#hostname {echo '' | tee /logdir/\*.log > /dev/null}
expect yes/no { send yes\n ; exp_continue }
expect password: { send $pass\n }
expect eof
";
In this command, expect displays the spawned command as spawn ssh user#hostname echo '' | tee /logdir/\*.log > /dev/null Which means that the \ was not removed. Why is it different? (If I don't escape the asterisk, like tee /logdir/*.log, it does work. But I don't understand what is working differently from the above case?)
That's how Tcl deals with backslashes.
[bash] # tclsh
% puts \*
*
% puts "\*"
*
% puts {\*}
\*
%
According to Tcl doc:
If a backslash (\) appears within a word then backslash substitution occurs. In all cases but those described below the backslash is dropped and the following character is treated as an ordinary character and included in the word. The following table lists the backslash sequences that are handled specially, along with the value that replaces each sequence.
[...]
Backslash substitution is not performed on words enclosed in braces, except for backslash-newline as described above.

Expect script return value

I'm including simple Expect commands within a Bash script (I know I could be just writing a pure Expect script, but I would like to get it to work from within Bash).
The script is below:
#!/bin/bash
OUTPUT=$(expect -c '
spawn ssh mihail911#blah.org
expect "password:"
send "dog\r"
')
Upon ssh'ing to the above address, it will return something of the form mihail911's password: on the prompt, so I think my expect line is valid.
When I run this my script does not print anything. It does not even show the password: prompt. In general, even if I manually provide an incorrect password, I will receive a Incorrect password-type response prompt. Why is nothing printing and how can I get my script to execute properly?
I have tried debugging by using the -d flag and it seems to show that at least the first expect prompt is being matched properly.
In addition, what values should I expect in the OUTPUT variable? When I echo this variable, it simply prints the first the first command of the expect portion of the script and then mihail911's password:. Is this what it's supposed to be printing?
Use:
#!/bin/bash
OUTPUT=$(expect -c '
# To suppress any other form of output generated by spawned process
log_user 0
spawn ssh dinesh#xxx.xxx.xx.xxx
# To match some common prompts. Update it as per your needs.
# To match literal dollar, it is escaped with backslash
set prompt "#|>|\\$"
expect {
eof {puts "Connection rejected by the host"; exit 0}
timeout {puts "Unable to access the host"; exit 0;}
"password:"
}
send "root\r"
expect {
timeout {puts "Unable to access the host"; exit 0;}
-re $prompt
}
send "date\r"
# Matching only the date cmd output alone
expect {
timeout { puts "Unable to access the host";exit 0}
-re "\n(\[^\r]*)\r"
}
send_user "$expect_out(1,string)\n"
exit 1
')
echo "Expect's return value: $?"; # Printing value returned from 'Expect'
echo "Expect Output: $OUTPUT"
Output:
dinesh#MyPC:~/stackoverflow$ ./Meric
Expect's return value: 1
Expect Output: Wed Sep 2 09:35:14 IST 2015
dinesh#MyPC:~/stackoverflow$

Bash- How to pack escape character into a special character ($) inside a string?

I have a variable in bash return from a function call getpassword() which return "apple$123123"
FOO=`getpassword`
I would like to use FOO variable which contains $ inside and pass into expect program
expect -c "\
set timeout 90
set env(TERM)
spawn rdesktop 192.168.11.1
expect \"Password:\"
send -- \"'${FOO}\n'\"
interact
"
}
There is an error coming out as $FOO contain dollar-sign
Password: can't read "123": no such variable
while executing
How can i solve this kind of problem? The way i think is that to pack escape character into FOO, using sed?
Thanks
You could try this:
# below is purposely on one line -- it sets the FOO env var
# only for the duration of the expect command.
FOO=$(getpassword) expect -c '
set timeout 90
set env(TERM) {are you missing something here?}
spawn rdesktop 192.168.11.1
expect "Password:"
send -- "$env(FOO)\r" # you send '\r' not '\n'
interact
'
Using single quotes make it easier to write (and read) the expect script (without all the backslashes). Testing:
$ getpassword() { echo 'abc$123'; }
$ FOO=$(getpassword) expect -c 'puts "pw=$env(FOO)"'
pw=abc$123
$ echo "> $FOO <"
> <

Run cat on remote computer and send output a variable using expect

I have a bash+expect script which has to connect via ssh to the remote comp (and i can't use ssh keys, need password identification in here), read the file there, find specific line with the "hostname" (like "hostname aaaa1111") and store this hostname into the variable to be used after while. How can i get the value of the "hostname" parameter? I thought that line content will be in $expect_out(buffer) variable (so i can scan it and analyze), but it's not. My script is:
#!/bin/bash
----bash part----
/usr/bin/expect << ENDOFEXPECT
spawn bash -c "ssh root#$IP"
expect "password:"
send "xxxx\r"
expect ":~#"
send "cat /etc/rc.d/rc.local |grep hostname \r"
expect ":~#"
set line $expect_out(buffer)
puts "line = $line, expect_out(buffer) = $expect_out(buffer)"
...more script...
ENDOFEXPECT
When i try to see line variable, i see only this: line = , expect_out(buffer) = (buffer) What is the right way to get the line from the file into the variable?
Or is it possible to open the file on the remote computer with expect, scan the file and get what i need to the variable?
Here http://en.wikipedia.org/wiki/Expect there is an example:
# Send the prebuilt command, and then wait for another shell prompt.
send "$my_command\r"
expect "%"
# Capture the results of the command into a variable. This can be displayed,
set results $expect_out(buffer)
seems that it doesn't work in this case?
You might just want to try and do it all from expect, as expect can control bash.
The following should do what you've described. Not sure if this is exactly what you are trying to do.
#!/bin/sh
# the next line restarts using tclsh \
exec expect "$0" "$#"
spawn bash
send "ssh root#$IP\r"
expect "password:"
send "xxxx\r"
expect ":~#"
send "cat /etc/rc.d/rc.local |grep hostname \n"
expect ":~#"
set extractedOutput $expect_out(buffer)
set list [split $extractedOutput "\n"]
foreach line $list {
set re {(?x)
.*
(*)
-S.*
}
regexp $re $line total extractedValue
if {[info exists extractedValue] && [string length $extractedValue] > 1} {
set exportValue $extractedValue
break # We've got a match!
}
send "exit\r" # disconnect from the ssh session
if {[info exists exportValue] && [string length $exportValue] > 1}{
send "export VARIABLE $exportValue\r"
} else {
send_user "No exportValue was found - exiting\n"
send "exit\r"
close
exit 1
}
# now you can do more things in bash if you like

Resources