I have the following shell(/expect) script.
#!/bin/bash
expect -c '
set user [lindex $argv 0]
set password [lindex $argv 1]
set ipaddr [lindex $argv 2]
set timeout 10
spawn ssh $user#$ipaddr mkdir -p ~/Tested
expect "*?assword:*"
send -- "$password\r"
interact
'
when I run the script as follows
. test.sh abcd test 10.xx.xxx.xxx
It gives the following error
can't read "argv": no such variable
while executing
"lindex $argv 0"
invoked from within
"set user [lindex $argv 0]"
Does anybody know what the error is , if I replace [lindex $argv 0] lines with actual value the script runs.
Thanks in advance.
The -c flag in expect provides a way of executing commands specified on the command line rather than in a script.
In general, -c is flag is used in command line used to execute commands before a script takes control.
They are used as below.
expect -c "set debug 1" myscript.exp
Inside myscript.exp, you can check the value of this variable:
if [info exists debug] {
puts "debugging mode: on"
}
else {
set debug 0
# imagine more commands here
if $debug {puts "value of x = $x"}
}
When the script is run, it checks if debug is defined by evaluating info exists, a
Tcl command which returns 1 if the variable is defined or 0 if it is not. If it is defined,
the script can then test it later to determine if it should print debugging information internal to the script. The else clause sets debug to 0 just so that later a simple if $debug test can be used.
Now, lets come to your question. You are using the variable argv which is the command line argument list passed to some script and with -c flag in use, you cant make use of it since argv is intended to be used inside a script, not outside.
Instead of doing this way, you can put your code inside a script file and call the code as below.
expect yourscript.exp username pwd ip_address
If you still interested in command line arguments, then you can try what fwilson suggested in comments.
expect yourscript.exp $1 $2 $3
With this, yourscript.exp will get the arguments from the shell script.
Reference : Exploring Expect
Related
This question already has an answer here:
Parsing command line using argc and argv in expect
(1 answer)
Closed 3 years ago.
I would like to remove all log files inside directory /var/log/$some_project/
I can remove them using shell command :
sudo rm /var/log/$some_project/*.log
But I have created expect script as shown below. Where I pass the PASS (my system password) and FILES (/var/log/$some_project/*.log) but it does not delete the files. It deleted only one file the first one.
I also tried instead of passing FILES/*.log, I just passed /var/log/$some_project and use the second script. But still, I am not able to remove all the log files.
I have also tried passing each file to expect script and remove still it does not work.
First Script
set timeout -1
set PASS [lindex $argv 0];
set FILES [lindex $argv 1];
spawn sudo rm $FILES
expect "Password:"
send $PASS\r
set timeout -1
exit 0
expect eof
Second Script
set timeout -1
set PASS [lindex $argv 0];
set FILES [lindex $argv 1];
spawn sudo rm $FILES/*.log
expect "Password:"
send $PASS\r
set timeout -1
exit 0
expect eof
Please, I would want to expect to understand the wildcard character and remove the files from the directory specified.
If you pass a wildcard expression to a script, the shell in which you run the script expands the wildcard before starting the script. So by the time Expect runs, [lindex $argv 1] really contains only the first one of the files you want to removed
Am working on a script to ssh into list of servers using expect tool. Getting below error while running it
./script
#!/usr/local/bin/expect -f
while /usr/bin/read hostname
do
spawn ssh user#$hostname
expect "user#$hostname's password"
send "resuidt\n"
expect "user#$hostname"
interact
done < srvlist
Below is my error:
missing operand at _#_
in expression "_#_/usr/bin/read"
(parsing expression "/usr/bin/read")
invoked from within
"while /usr/bin/read hostname"
(file "./script" line 3)
Need help to fix this error.
You are writing an Expect program, which is basically a Tcl program. Your while loop is not Tcl syntax, but looks like a (Posix/Ksh/Bash/Zsh)-shell script.
You have to make up your mind: Write everything in Tcl, or split your application into two files: One (in shell script) as "main program", and a separate expect script, which will be called by the shell script.
As user1934428 indicates you are using bash-type while loop syntax.
Below is one example of how to make an expect script perform the actions you want.
#!/usr/local/bin/expect -f
set file hostname
set user myusername
set passwd mypassword
set f [open $file]
foreach target [split [read $f] "\n"] {
spawn ssh $user#$target
expect {
timeout {send_user "Expect Timeout\n" ; exit}
"password:"
}
send "$passwd\r"
expect {
timeout {send_user "Expect Timeout\n" ; exit}
"$user#$target"
}
interact
}
close $f
I included timeouts in the expect sections because I've found if you do not add these safety mechanisms the expect script can proceed even without the proper responses.
if you want to use shell variables directly into the expect script then you have to pass those variables as $env(shell_variable_name) inside the expect script
example:spawn ssh $env(myusername)#$env(hostname)
I have an expect script that executes the commands given as arguments like this:
!/usr/bin/expect
spawn telnet ip
for {set i 0} {$i < $argc} {incr i 1} {
set cmd [lindex $argv $i]
send "$cmd\n"
}
And I can call it with whatever commands I want to execute on the remote device e.g. my_expect_script "cd /home" "ls" "mkdir mydir". I would like to have something executed before this script by default. My idea was to write another script like this:
#!/bin/bash
do-something
my_expect_script "$*"
Now if I do so the my_expect_script seems to get only one argument. In my example only the cdpart would be executed.
Is there a simple way to pass the arguments as seperate arguments but at once?
Just found the solution here. I have to adapt the second script as follows:
#!/bin/bash
do-something
my_expect_script "$#"
I always thought $*and $# do exactly the same.
I am writing a Bash script and using Expect to do sftp. Now in the Expect block I want to access a Bash variable in a conditional statement. But, I am unable to do so. How can do this?
Also, the execution of this script is controlled from a C program and I want redirect the output to a log file (which again is dynamic). Can I do that and suppress all the output on standard output.
Here is the code:
!/usr/bin/bash
host=$1
user=$2
pass=$3
action=$4
path=$5
echo "Starting...."
function doAction {
strAction="\""$action"\""
echo $strAction
/usr/bin/expect <<EOF > logfile.txt
**set bashaction $strAction**
spawn sftp $user#$host
expect "password:"
send "$pass\r"
expect"sftp>"
send "cd $path\r"
**if {$bashaction == "TEST"} {**
expect "sftp>"
send "prompt\r"
}
expect "sftp>"
send <sftp command>
expect "sftp>"
send_user "quit\n"
exit
EOF
}
doAction
echo "DONE....."
For 1. using an Expect script instead worked.
For the logging issue, using log_user 0 and log_file -a <file> helped.
You don't need to use Bash. Expect can handle all that:
#!/usr/bin/expect
set host [lindex $argv 0]
set user [lindex $argv 1]
set pass [lindex $argv 2]
set action [lindex $argv 3]
set path [lindex $argv 4]
puts "Starting...."
puts "\"$action\""
spawn sftp $user#$host
expect "password:"
send "$pass\r"
expect"sftp>"
send "cd $path\r"
if {$action == "TEST"} {
# Do something
} else {
# Do something else
}
expect "sftp>"
send_user "quit\r"
puts "DONE....."
Coming from Bash, the Tcl/Expect syntax is a little strange, but you should not have any problem expanding the above skeleton.
Accessing Environment Variables from TCL and Expect
Since you are calling this Expect script from another process, you can make use of environment variables. For example, if your parent process has exported action to the environment, then you can access its value within your expect script with:
$::env(action)
In Bash, you can mark the variable for export with the export builtin. For example:
export action
Since I'm not sure how you're invoking the Expect script from C, it's up to you to make sure the variable is properly exported.
Disable Logging to Standard Output
To disable logging to standard output from spawned processes, Expect provides the log_user command. You can prevent your spawned processes from writing to stdout with log_user 0.
The expect(1) manual says:
By default, the send/expect dialogue is logged to stdout (and a
logfile if open). The logging to stdout is disabled by the command
"log_user 0" and reenabled by "log_user 1". Logging to the logfile
is unchanged.
This doesn't actually close standard output, which is generally not what you want anyway. Doing so will cause anything that writes to stdout to throw an error like this:
can not find channel named "stdout"
while executing
"puts hello"
(file "/tmp/foo" line 8)
To suppress output to the standard output you can use
command here >/dev/null 2>/dev/null
To write to a log file, you can use similar piping (> or >>), or the tee command if you want to write the output in the middle of a long pipe.
I have a script(dobrt) which upon executing asks for a password.How can i write a script which executes dobrt and automatically supplies the password it asks for.
when i execute ./dobrt -p file.txt , the system asks for a password. I want the password to be sent in automatically by the script. Here is the output
$ ./dobrt -p file.txt
Found 194 tests to execute
------------ 2010 February 11 11:27:33 ------------
Password: ***************
I tried using shell and expecxt scripts for this. here is what i did.
I have 2 scripts. I call the second script(run_dobrt.exp) from the first one(run_dobrt.sh).
Script 1 : run_dobrt.sh
#!/bin/ksh
TESTCASE_HOME="/home/abhijeet/code/testcases";
TESTCASE_LIST="file.txt";
PASSWORD="*****";
echo "Running Expect Script"
`./run_dobrt.exp $TESTCASE_HOME $TESTCASE_LIST $PASSWORD`
Script 2: run_dobrt.exp
#!/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
Now when i run run_dobrt.sh i get the following error
run_dobrt.sh[20]: spawn: not found
How to get rid of this error and get this task done? Please help.
What is dobrt? is a self-made program? If this is the case I think you will have to recode it to parse an extra argument that accepts the password. Then you will be able to pass this passowrd to dobrt just as you do it like "-p file.txt" in the command line (through a script).
I see two problems:
In the last line of your shell script, remove the back-quotes `` around the command,
they will cause the output of the expect script to be executed as a shell command.
In the expect script, change
set PASSWORD [lindex $argv 3];
to
set PASSWORD [lindex $argv 2];
you are skipping an argument.
If the password is the only input dobrt prompts for, you could try this:
Script 1 : run_dobrt.sh
#!/bin/ksh
TESTCASE_HOME="/home/abhijeet/code/testcases";
TESTCASE_LIST="file.txt";
PASSWORD="*****";
./run_dobrt.exp $TESTCASE_HOME $TESTCASE_LIST << EOF
$PASSWORD
EOF