output from expect is not complete - linux

I have this script in order to make rsync with another server, the propossal is to get arround 1600 files, this script as two variables, date and hour, so, I send these two values with shell script then I pass the values.
Expect script:
#!/usr/bin/expect
set DIR_DATE [lrange $argv 0 0]
# Define date variable.
set DT_HOUR [lrange $argv 1 1]
# Define hour variable.
spawn rsync -avzb -e ssh user#IPSERVER:/SOURCE_DIR/$DIR_DATE/A$DIR_DATE.$DT_HOUR*.txt /TARGET_DIR/$DIR_DATE/
expect "password:"
send "PASSWORD\r"
#interact
expect eof
And the shell script is:
#!/bin/bash
***HERE is the code to get date and hour variable: DT_DATE,DT_HOUR; then, next step is run the expect script***
${DIR_BIN}/rsync_expect.sh ${DT_DATE} ${DT_HOUR}
You can note, in the expect script, I comment "interactive" word, because:
If it is not comment and run manually the script, it runs very well, it get 1600 files.
If it is commented, and run through the shell script, it only get arround 50 files and that's off.
So, any sugestion in order to get all files using shell scripts?

You're probably timing out: 50 files is probably what you can transfer in (default) 10 seconds. Add this before you spawn: set timeout -1
".sh" is a bad file extension for an expect script: use ".exp"
The lrange command returns a list. Use lassign $argv DIR_DATE DT_HOUR

Related

Get expect to take a variable with whitespaces in it [duplicate]

This question already has an answer here:
When should I double-quote a parameter expansion? [duplicate]
(1 answer)
Closed 3 years ago.
In my expect script I have two variables I would like to add. Both of them will be variables into the script.
hello="My Life"
world="is wonderful"
./script.sh $hello $world
in script.sh
#!/usr/bin/expect
set timeout 10
match_max 100000000
set first_var [lindex $argv 0]
set second_var [lindex $argv 1]
Currently,
first_var="My"
second_var="Life"
The code below works as expected when don't pass in them in as variables.
./script.sh 'My Life' 'is wonderful'
I need to know how to have that script take in the variables and still ignore white space within them.
You must pass the variables within quotes as well;
./script.sh "$hello" "$world"
The way Bash expansion works, these variables will be expanded out before the script is run. It will be the same as if the command were run as
./script "My life" "is wonderful"
The quotes around parameters indicate to the shell not to split via the field separator.

Tcl expects output from tclsh to shell script

I'm searching for last few days for solution to my problem so finally I came here.
I got to write a Tcl script that should be opened from a Linux/Debian system. The problem is, that the script should log into a Cisco router and then go into the special tclsh mode, where it should get the SNMP value which represents txload. After a moment I get the value in tclsh mode (which supports SNMP), but I can't get it back to my script. It still exists only in router tclsh mode. My script should change some other values depending on the value I already have in tclsh, but tclsh is not needed anymore.
So here's my question: How can I get the $ifnum value from tclsh but I could still use in that script for some loops, because I need to make some loops where the $ifnum will be the condition?
As you can see, the script is not finished yet, but as I said, I'm stuck here and trying to figure it out:
#!/usr/bin/expect -f
set gateway [lindex $argv 0]
set serial [lindex $argv 1]
set timeout 5
spawn telnet $gateway
expect "Password:"
send "cisco\r"
expect "*>"
send "en\r"
expect "Password:"
send "cisco\r"
expect "*#"
send "set ifnumstr \[snmp_getone odczyt 1.3.6.1.4.1.9.2.2.1.1.24.6\]\r"
expect "*}"
send "regexp \{val='(\[0-9\]*)'\} \$ifnumstr \{\} ifnum \r"
expect "*#"
send "puts \$ifnum \r"
expect "*#"
I'd make it print out the thing you're looking for between markers, and then use expect in its RE matching mode to grab the value.
send "puts \"if\\>\$ifnum<if\"\r"
expect -re {if>(.*?)<if}
# Save the value in a variable in the *local* script, not the remote one
set ifnum $expect_out(1,string)

Shebang causes script to fail

I'm quite bad at bash, and I try to make a script to connect to all my switches with openSSH in order to make some configuration.
I created an array containing all my 25 switches, and then I used a loop to open SSH connection with each of them.
As I'm on Windows and using bash, I've just installed Cygwin.
However, I had to use expect and writing my password in plain text as the switches are quite poor and that is the best way for me (I won't manually put my RSA key on every single switch as it would take me as much time as writing manually the configuration on every switch).
I use the shebang #!/usr/bin/expect -f to make bash recognize expect. When I do this, the expect syntax (spawn, expect, interact) works perfectly, but my array doesn't work.
I get the following error message:
extra characters after close-quote
while executing "arrayname=("172.21.21.20" "172.20.55.55" ... "
When I change the shebang, and use #!/bin/bash, expect is not found anymore :
./stationsnmp.sh: line 20: spawn : command not found couldn't read
./stationsnmp.sh: line 24: send : command not found couldn't read
file "assword": no such file or directory ./stationsnmp.sh: line 27:
send : command not found ./stationsnmp.sh: line 28: interact :
command not found
I'm really not a pro in bash, which explains I can't get this little problem... Some help would be welcome.
EDIT : Below is a part of my code
#!/bin/bash
switch=("172.20.0.229" "172.20.0.232" "172.20.0.233" "172.21.0.15" "172.21.0.16" "172.21.2.1" "172.20.2.250" "172.21.3.1" "172.20.3.250" "172.21.4.1" "172.20.4.250" "172.21.6.1" "172.20.6.250" "172.21.7.1" "172.20.7.250" "172.21.8.1" "172.20.8.250" "172.20.9.250" "172.21.9.1" "172.21.10.1" "172.20.10.250" "172.21.11.1" "172.20.11.250" "172.21.12.1" "172.21.12.250")
nmb=`echo ${#switch[#]}`
set timeout 3
for ((ii=0; ii<=$nmb; ii++))
#for ii in {0..${#switch[#]}}
do
if [ ${switch[$ii]:5:1} -eq 1 ]
then
ipdc=`echo ${switch[ii]} | grep -o -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.'`"10"
spawn ssh admin#switch[$ii]
expect "*assword*"
send "PASS\r"
interact
exit
fi
done
You are mixing bash and expect, those are two entirely different languages. You probably want to have a bash wrapper script with proper option handling (see getopts) which takes a list of IP addresses and execute your expect script for each IP address passed to your bash-wrapper. If your expect script is small you might want to embed it into your shell script as opposed to having it in a separate file.
EDIT:
#!/bin/bash
switches=("172.20.0.229" "172.20.0.232")
for ip in "${switches[#]}"; do
expect "${ip}" <<-'EOT'
set host [lindex $argv 0]
set timeout 3
spawn ssh -l admin $host
expect "*assword*"
send "PASS\r"
interact
exit
EOT
done

"command not found" errors in expect script executed by shell script

I am trying to implement "shell script calling expect script" so that it does not prompt the user for entering ssh password every time. I started with Using a variable's value as password for scp, ssh etc. instead of prompting for user input every time and understood that I should have a .sh file and a .exp file. I have expect installed in my system (running expect -v shows expect version 5.43.0).
In my upload-to-server.sh file I have
cd $SOURCE_PATH/shell
./password.exp $DESTINATION_PATH $SSH_CREDENTIALS $PROJECT_INSTALLATION_PATH $PASSWORD
And in my password.exp file I have
#!/usr/bin/expect -f
set DESTINATION_PATH [lindex $argv 0];
set SSH_CREDENTIALS [lindex $argv 1];
set PROJECT_INSTALLATION_PATH [lindex $argv 2];
set PASSWORD [lindex $argv 3];
spawn scp $DESTINATION_PATH/exam.tar $SSH_CREDENTIALS':/'$PROJECT_INSTALLATION_PATH
expect "password:"
send $PASSWORD"\n";
interact
On running the upload-to-server.sh file I get the following error -
./password.exp: line 9: spawn: command not found
couldn't read file "password:": no such file or directory
./password.exp: line 11: send: command not found
./password.exp: line 12: interact: command not found
I arrived at the above code (in the exp file) from multiple sources (without understanding much basics). In one source the code is like this
#!/usr/local/bin/expect
spawn sftp -b cmdFile user#yourserver.com
expect "password:"
send "shhh!\n";
interact
Whereas in another source like this
#!/usr/local/bin/expect -f
set TESTCASE_HOME [lindex $argv 0];
set TESTCASE_LIST [lindex $argv 1];
set PASSWORD [lindex $argv 3];
set timeout 200
spawn $TESTCASE_HOME/dobrt -p $TESTCASE_HOME/$TESTCASE_LIST
expect "*?assword:*" {send -- "$PASSWORD\r";}
expect eof
There are some differences there -
there is an extra -f in the #!/usr/local/bin/expect line
expect "?assword:" {send -- "$PASSWORD\r";} is different from expect "password:"
send "shhh!\n";
interact replaced with expect eof.
This is my first expect script so don't have much idea what to code. Any pointers?
Thanks,
Sandeepan
Don't do any of this! You should use public key authentication as the comment above suggests. The way you're going leaves passwords in the clear and is fragile.
Public key authentication is way easier to setup, for example: setup instructions
Are you sure you're doing
./script.exp
And not
. ./script.exp
?? The latter would have the shell trying to interpret the expect program.
Fully agree that ssh keys are the correct solution though.

How can EXPECT interpret an escaped character to a command character

I'd like to be able to pass in a long command to expect. It's a multiple command somehow. First here's my expect script
#!/usr/bin/expect -f
set timeout -1
spawn telnet xxx.xxx.xxx.xxx
expect "*?username:*"
send "someusername\r"
expect "*?assword:*"
send "somepassword\r"
# Here's the command I'd like to pass from the command prompt
set command [lindex $argv 0]
send "$command\r"
send "exit\r"
I would then run this script as so:
./expectscript "mkdir /usr/local/dir1\ncd /usr/local/dir1\ntouch testfile"
Notice that I put "\n" to initiate an enter as though I'm processing the command before moving to the next.
I know you could separate the commands with ";", but for this particular exercise, I'd like to be able have expect interpret the "\n" with a "\r" so that, expect would behave as though it were like this:
send "mkdir /usr/local/dir1\r"
send "cd /usr/local/dir1\r"
send "touch testfile\r"
The question then becomes how can expect interpret the "\n" to be "\r"? I've tried putting the "\r" in the argument instead of "\n", but that doesn't work.
Thanks for the input.
When I do a simple experiment, I find that the \n in the argument is not converted by my shell (bash) into a newline; it remains a literal. You can check this out for yourself by just using puts to print out the command line argument, like this:
puts [lindex $argv 0]
Working around this requires a little bit of work to split things. Alas, Tcl's split command does not split on multi-character sequences (it splits on many different characters at once instead) so we'll need a different approach. However, Tcllib has exactly what we need: the splitx command. With that, we do this (based on #tensaix2j's answer):
#!/usr/bin/expect -f
package require Expect;   # Good practice to put this explicitly
package require textutil::split; # Part of Tcllib
# ... add your stuff here ...
foreach line [textutil::split::splitx [lindex $argv 0] {\\n}] {
send "$line\r"
# Wait for response and/or prompt?
}
# ... add your stuff here ...
If you don't have Tcllib installed and configured for use with Expect, you can also snarf the code for splitx directly out of the code (find it online here) as long as you internally acknowledge the license it's under (standard Tcl licensing rules).
foreach cmd [ split $command \n ] {
send "$cmd\r\n"
}

Resources