I'm trying to schedule an expect script that I have written with Cron. It is not working as expected. This is my code, my entry in the cron file, and the shell file containing the command to run the script. Any help is appreciated.
#!/usr/bin/expect
# Set timeout
set timeout 1
# Set the user and pass
set user "user"
set pass "pass"
# Get the lists of hosts, one per line
set f [open "hosts.txt"]
set hosts [split [read $f] "\n"]
close $f
# Get the commands to run, one per line
set f [open "commands.txt"]
set commands [split [read -nonewline $f] "\n"]
close $f
# Iterate over the hosts
foreach host $hosts {
# Establish ssh conn
spawn ssh $user#$host
expect "password:"
send "$pass\r"
# Iterate over the commands
foreach cmd $commands {
expect "$ "
send "$cmd\r"
expect "password:"
send "$pass\r"
expect "$ "
}
}
0,15,30,45 * * * * /home/car02fv/updatelogs.sh #fetch application logs (dbg,api,ch)
#!/bin/sh
rm goxsd1697/* goxsd1698/* goxsd1699/* goxsd1700/* | /home/car02fv/getlogs.sh
This answer comes from the discussion I had with Camilo above.
To check the error log and running the script every 15 minutes,
*/15 * * * * /home/car02fv/updatelogs.sh >/tmp/cron_out 2>&1
was run to check the output file /tmp/cron_out, using
vi /tmp/cron_out
Also, you need to give permission to the file by chmod u+x /home/car02fv/updatelogs.sh to make the script executable.
You are not providing the full path to the files you need to read. Cron scripts usually have PWD as /.
Assuming the "hosts.txt" and "commands.txt" are in /home/car02fv, you can do
0,15,30,45 * * * * cd /home/car02fv && ./updatelogs.sh
However, this is more robust: assuming you keep those text files in the same place as the script file: add to the expect script (near the top)
set dir [file dirname [info script]]
then, open the files like this:
set hostfile [file join $dir hosts.txt]
if {![file exists $hostfile]} {error "$hostfile does not exist"}
set f [open $hostfile]
# ...
set cmdfile [file join $dir commands.txt]
if {![file exists $cmdfile]} {error "$cmdfile does not exist"}
set f [open $hoscmdfiletfile]
and the cron entry stays like you have it.
BTW, ".sh" is a misleading file extension for an expect file.
#!/bin/sh
while true; do
rm goxsd1697/* goxsd1698/* goxsd1699/* goxsd1700/* | /home/car02fv/getlogs.sh
sleep 120
done
Related
after the scp completes in this code an additional prompt appears. I've tried several things to prevent this from happening, but it still appears. To be clear, two prompts appear after the for loop and then the program continues.
#!/usr/bin/expect
# Set timeout
set timeout 1
# Set the user and pass
set user "user"
set pass "pass"
# Get the lists of hosts, one per line
set f [open "hosts.txt"]
set hosts [split [read $f] "\n"]
close $f
# Get the commands to run, one per line
set f [open "commands.txt"]
set commands [split [read $f] "\n"]
close $f
# Clear console
set clear "clear"
# Iterate over the hosts
foreach host $hosts {
# Establish ssh conn
spawn ssh $user#$host
expect "password:"
send "$pass\r"
# Iterate over the commands
foreach cmd $commands {
expect "$ "
send "$cmd\r"
expect "password:"
send "$pass\r"
}
# Tidy up
# expect "$ "
# send "exit\r"
# expect eof
# send "close"
}
Because both your hosts and commands lists end with an empty string. Verify with puts [list $hosts $commands]
So you send an empty command, which is just "hitting enter". Then you wait for the password prompt, time-out in 1 second, and carry on with the program.
This is due to the way you're reading the files: read grabs the file contents, including the file's trailing newline. Then, when you split the string on newline, the list will include the empty string following the trailing newline.
Do this instead:
set commands [split [read -nonewline $f] "\n"]
# ........................^^^^^^^^^^
See https://tcl.tk/man/tcl8.6/TclCmd/read.htm
You could also do this
set f [open "commands.txt"]
while {[gets $f line] != -1} {
# skip empty lines and commented lines (optional)
if {[regexp {^\s*(#|$)} $line]} continue
lappend commands [string trim $line]
}
close $f
I have a file abc/xyz.log in log directory. How can I find if the file exists or not in SystemVerilog class. If the file exists I want to delete the file.
Thanks.
You can use $fopen and it returns 0 if it doesn't exist. If it does exist, $fclose the file and then use $system("shell command") to delete it.
Using the Unix utility "test" (see "man test") through a $system call can do the job. It can also be done through direct C using the stat() function (much more cumbersome). This example can be leveraged to do what you want. In this case it checks for the existence of a directory and it not found, attempts to create it.
string report_dir;
report_dir = {SIM_ROOT,"/",PROJ_NAME,"/",TECH_PROCESS,"/",LOGNAME,"/doc/functional"};
if ($system($sformatf("/usr/bin/test -d %s", report_dir)) != 0) begin
$display("INFO: creating output directory %s", report_dir);
if($system($sformatf("mkdir -p %s", report_dir)) != 0) begin
$display("ERROR: mkdir -p %s returned an error", report_dir);
$fatal(0);
end
end
if($system($sformatf("/usr/bin/test -d %s -o -w %s", report_dir, report_dir)) != 0) begin
$display("ERROR: output directory %s does not exist or is not writeable", report_dir);
$fatal(0);
end
I need to validate whether DB connection is success/failure.
This is my code
report=`sqlplus -S /nolog << EOF
WHENEVER OSERROR EXIT 9;
WHENEVER SQLERROR EXIT SQL.SQLCODE;
connect <<username>>/<<Password>>#hostname:port
set linesize 1500
set trimspool on
set verify off
set termout off
set echo off
set feedback off
set heading on
set pagesize 0
spool extract.csv
<<My SQL Query>>
spool off;
exit;
EOF`
I have tried the below option based on the thread Managing error handling while running sqlplus from shell scripts but its picking the first cell value rather than the connection status.
if [ $report != 0 ]
then
echo "Connection Issue"
echo "Error code $sql_return_code"
exit 0;`enter code here`
fi
Please advise.
I needed something similar but executed it a bit differently.
First, I have list.txt which contains the databases that I would like to test. I am using wallet connections but this could be edited to hold username/password.
list.txt:
DB01 INSTANCE1.SCHEMA1
DB02 INSTANCE2.SCHEMA2
DB03 INSTANCE3.SCHEMA3
DB04 INSTANCE4.SCHEMA4
I have OK.sql which contains the query that I want to run on each database.
OK.sql:
select 'OK' from dual;
exit
Last, I user test.sh to read list.txt, attempt to connect and run OK.sql on each line, and record the result in (drumroll) result.txt.
test.sh:
. /etc/profile
rm result.txt
while read -r name wallet; do
echo "BEGIN-"$name
if (sqlplus -S /#$wallet #OK.sql < /dev/null | grep -e 'OK'); then
echo $name "GOOD" >> result.txt
else
echo $name "BAD" >> result.txt
fi
echo "END-"$name
done < list.txt
After the run check your result.txt.
result.txt:
DB01 BAD
DB02 GOOD
DB03 GOOD
DB04 GOOD
I hope this helps.
I'm developing a script which in turn invokes several other scripts (.ksh). And basically when one of them fail they shouldn't proceed to the next one. So I tried checking for the return code in one script that involves bteq (Basic Teradata Query) session. Please find below the scenario:
bteq <<EOF!
.run file ${TGTRUNFILEN} ;
.maxerror 1;
.set width 245;
...
...
sel * from table ;
.if ACTIVITYCOUNT <> 0 then .GOTO QUIT
.os mail command "error msg"
exit 1;
.LABEL QUIT
.quit;
EOF!
echo $rcode
rcode=$?
if [[ $rcode != 0 ]]
then
echo "$0: Insufficient Perm Space : username " >&2
exit 4
fi
Here,the script fails and I can see the log saying failed with return code 1, but why isn't the text "$0:Insufficient Perm Space : Username" displayed. I think it exits the entire script, but I need this fixed somehow.
Can someone kindly help me on this?
Hi Thanks a ton for responding.I found a way to overcome this.I just added 'set' command like this.
set +e
bteq <<EOF!
...
...
EOF!
rcode=$?
set -e
Works fine for me.
Cheers
Since I am new to unix scripting. I am running a SQL statement in ASE ISQL, and if SQL statement gives some result then I need to mail that result to a particular users. And if SQL is not returning any result then mail should not be sent.
The Sample Script I have wriiten is:
#!/bin/ksh
isql -U$DBO -S$DSQUERY -D$DBNAME -P$PASSWORD << END
go
select * from 'Table'
go
if (##rowcount !=0)
mailx -s "Hello" XYZ#gmail.com
END
Please let me know where I am going wrong?
I think you need to capture the output of the SQL into a shell variable, and then test the result before sending the email, roughly like:
#!/bin/ksh
num=$(isql -U$DBO -S$DSQUERY -D$DBNAME -P$PASSWORD << END
select count(*) from 'Table'
go
END
)
if [ "$num" -gt 0 ]
then mailx -s "Hello" XYZ#gmail.com < /dev/null
fi
I am assuming that the isql program will only print the number and not any headings or other information. If it is more verbose, then you have to do a more sensitive test.
Note, too, that COUNT(*) is quicker and more accurately what you're after than your 'select everything and count how many rows there were' version.
Actually my problem is if my SQL statement is returning any result then only that resultset should be sent in a mail.
Then I'd use:
#!/bin/ksh
tmp=${TMPDIR:-/tmp}/results.$$
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
isql -U$DBO -S$DSQUERY -D$DBNAME -P$PASSWORD << END > $tmp
select * from 'Table'
go
END
if [ -s $tmp ]
then mailx -s "Hello" XYZ#gmail.com < $tmp || exit 1
fi
rm -f $tmp
trap 0
exit 0
This captures the results in a file. If the file is not empty (-s) then it sends the file as the body of an email. Please change the subject to something more meaningful. Also, are you sure it is a good idea to send corporate email to a Gmail account?