Display resultset from database using shell script every 4 seconds - oracle

I am attempting todisplay a resultset from oracle database every 4 second using shell script. This is what I have so far, but it gives me the oracle version information and unformated results:
#!/bin/bash
RETVAL=`sqlplus "username/password#(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=HOSTNAME)(Port=1521))(CONNECT_DATA=(SID=SIDNAME)))" <<EOF
SET PAGESIZE 200 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
select user_id,user_work_class,sol_id,user_appl_name from upr where user_logged_on_flg = 'Y';
EXIT;
EOF`
if [ -z "$RETVAL" ]; then
echo "No rows returned from database"
exit 0
else
echo $RETVAL
fi
Any ideas or direction will be highly appreciated.

If your query returns rows, you can only take what is after the space to test.
Make code:
$RETVAL_TST= `echo $RETVAL | awk '{print $2}'`
if [ -z "$RETVAL_TST" ]; then
echo "No rows returned from database"
exit 0
else
echo $RETVAL
fi
but the column on which you test awk '{print $2}' must be a key and not empty.

To run the script every 4 seconds, you need to set up a loop with sleep.
If the script is called script.sh:
for i in {1..100} ; do sh script.sh ; sleep 4 ; done > output
That will run the script 100 times with intervals of 4 seconds between each run and save the output into a file called output.
Edit-
If you want the script to run indefinitely then the for loop isn't a great idea. As mentioned by #Kacper, the while loop is better suited to that-
while(true) ; do sh script.sh ; sleep 4 ; done > output

Related

PIPESTATUS[0] in BASH script

I am implementing a scenario in Unix Bash scripts. I have two scripts ABC.bash and XYZ.bash. There is one condition in ABC.bash when requester does not enter Y or y scripts exit with message and do not work further. ABC.bash working fine when runs alone.Problem arises when I run it from another bash script i.e. XYZ.bash. It does not check for exit condition. Syntax of logic in XYZ.bash.
echo "Calling ABC.bash from XYZ.bash"
ABC.bash $a $b | tee -a $LOGFILE; sleep 2
if [ ${PIPESTATUS[0]} = 0 ]
then
echo "Do some work"
else
echo "Check ABC.bash input"
exit 1
fi
But when ABC.bash $a $b exit with status 2 flow still goes to IF block rather than ELSE.In log I can see message as DEBUGMODE set to 0. I need this DEBUGMODE setting as it is required but want to exit if ABC.bash exit. Ideally it should go to ELSE part as ABC.bash exit with wrong user input.
Additionally I have set up DEBUGMODE option in XYZ.bash script. Like-
if [[ -z "$1" ]]
then
echo " ">> No input so default to 0"
DEBUGMODE=0
else
echo "DEBUGMODE set to $1"
DEBUGMODE=$1
fi
enter code here
The problem is that PIPESTATUS is a volatile variable. That is it will be reset as soon as any other command is executed. You need to remove the call to sleep 2 if you want to inspect the PIPESTATUS.
In your example, PIPESTATUS reflects the status of sleep 2. So replace
ABC.bash $a $b | tee -a $LOGFILE; sleep 2
if [ ${PIPESTATUS[0]} = 0 ]
by
ABC.bash $a $b | tee -a $LOGFILE; pstat=(${PIPESTATUS[#]}); sleep 2
if [ ${pstat[0]} = 0 ]
to save the status.
As best practice, unless the your code has full control over the any variable content, better to quote the variable. This will not prevent logical error (e.g, the extra sleep that modified the PIPESTATUS), but it will avoid accidental injection of code into the script (or unexpected syntax errors)
if [ "${PIPESTATUS[0]}" = 0 ] ; then

Shell Script For Loop Exits After Finishing First Loop

Code works fine until the last for loop.
It tries to login database. Either, it establish a successful connection with database or not, script gives output OK/NOT OK depending to the connection and then exit the shell script. What should I do to solve this?
#!/bin/bash
read -p 'Username: ' var_username
read -sp 'Password: ' var_password
filename="$1"
while read -r line; do
name=$(sed 's/#.*$//g; s/(.*$//g; s/=.*$//g; s/).*$//g')
done < "$filename"
#retval=$? | tail -n1|grep OK
for tns in $name
do
tnsping $tns
if [ $? -eq 1 ]; then
echo $tns 'tnsping i calismiyor' >>tnslatest.log
else
echo $tns 'tnsping i calisiyor' >>tnslatest.log
working_tns+=($tns)
fi
done
#The following lines do not work properly.#
for working in $working_tns
do
echo "exit" | sqlplus -L $var_username/$var_password#$working | grep
Connected > /dev/null
if [ $? -eq 0 ]
then
echo "OK"
else
echo "NOT OK"
fi
done
For example; my tnsnames.ora file contains 4 tns.
So, I want to have for output like OK or NOT OK in total.
Thanks in advance.

Bash script for searching a specific word in terminal output

I'm trying to implement a bash script who supposed to search for a word in a Python script terminal output.
The Python script doesn't stop so "&" in the end of the command is needed but the "if [ $? == 0 ] ; then" condition doesn't work.
How it can be solved?
Thanks, Gal.
#!/bin/bash
#Check if Pixhawk is connected
PORT=/dev/ttyPixhawk
end=$((SECONDS+3))
not_exists=f
/usr/local/bin/mavproxy.py --daemon --non-interactive --master=$PORT | grep 'Failed' &> /dev/null &
while [ $SECONDS -lt $end ] ; do
if [ $? == 0 ] ; then
not_exists=t
fi
sleep 1
done
if [ $not_exists=t ] ; then
echo "Not Exists"
else
echo "Exists"
fi
kill $(pgrep -f '/usr/local/bin/mavproxy.py')
Bash doesn't know anything about the output of background commands. Check for yourself with [ 5444 -lt 3 ] & echo $?.
your if statement wouldn't work in any case because $? checks for the return value of the most recent previous command, which in this case is your while loop.
You have a few different options. If you're waiting for some output, and you know how long it is in the output until whatever target you're looking for occurs, you can have the python write to a file and keep checking on the file size with a timeout for failure.
You can also continue with a simple timed approach as you have where you just check the output after a few seconds and decide success or failure based on that.
You can make your python script actually end, or provide more error messages, or write only the relevant parts to file that way.
Furthermore, you really should run your script through shellcheck.net to notice more problems.
You'll need to define your goal and use case more clearly to get real help; all we can really say is "your approach will not work, but there are definitely approaches which will work"
You are checking the status of grep command output inside while loop using $?. This can be done if $? is the next command to be fired after grep and if grep is not a back-group process . But in your script, $? will return the status of while [$SECONDS -lt $end ]. You can try to re-direct the output to a temp file and check it's status
/usr/local/bin/mavproxy.py --daemon --non-interactive --master=$PORT | grep 'Failed' &> tmp.txt &
sleep 3
# If file exists and it's size is greater than 0, [ -s File] will return true
if [ -s tmp.txt ]; then
echo 'pattern exists'
else
echo 'pattern not exists'
fi

Set call file to hang up after some time using Bash AGI

I'm trying to make a call using a call file on asterisk where it plays a file and hangs up after a given time whether the sound file has finished or not.
I have it working with this bash script as the AGI script:
#!/bin/bash
Duration="30"
file="sound.mp3"
while read VAR && [ -n ${VAR} ] ; do : ; done
echo "ANSWER"
read RESPONSE
echo 'SET AUTOHANGUP $Duration'
echo 'EXEC PLAYBACK "'$file'" ""'
read RESPONSE
exit 0
The problem is that the asterisk cdr logs show the call to last 30 seconds whether the the person on the other end has hung up or not...
Can anyone help?
OK this is embarrassing...
I cleaned up my code so that I could paste it on here and when I try again it seems to work how I want. Still don't know what then problem was but this code seems to work
#!/bin/bash
Duration="20"
file="soundfile"
while read VAR && [ -n ${VAR} ] ; do : ; done
echo "ANSWER"
read RESPONSE
echo 'SET AUTOHANGUP '$Duration''
echo 'EXEC PLAYBACK "'$file'" ""'
read RESPONSE
exit 0
You can use the signal facility. For example:
#!/bin/bash
times_up(){ echo "time is up, pens down."; exit 0; }
trap 'times_up' ALRM
(sleep 10;kill -0 $$ && kill -ALRM $$)&
s=0
while (true) do
sleep 1
echo "$s: do my stuff"
let s=$s+1
done

Run bash commands in parallel, track results and count

I was wondering how, if possible, I can create a simple job management in BASH to process several commands in parallel. That is, I have a big list of commands to run, and I'd like to have two of them running at any given time.
I know quite a bit about bash, so here are the requirements that make it tricky:
The commands have variable running time so I can't just spawn 2, wait, and then continue with the next two. As soon as one command is done a next command must be run.
The controlling process needs to know the exit code of each command so that it can keep a total of how many failed
I'm thinking somehow I can use trap but I don't see an easy way to get the exit value of a child inside the handler.
So, any ideas on how this can be done?
Well, here is some proof of concept code that should probably work, but it breaks bash: invalid command lines generated, hanging, and sometimes a core dump.
# need monitor mode for trap CHLD to work
set -m
# store the PIDs of the children being watched
declare -a child_pids
function child_done
{
echo "Child $1 result = $2"
}
function check_pid
{
# check if running
kill -s 0 $1
if [ $? == 0 ]; then
child_pids=("${child_pids[#]}" "$1")
else
wait $1
ret=$?
child_done $1 $ret
fi
}
# check by copying pids, clearing list and then checking each, check_pid
# will add back to the list if it is still running
function check_done
{
to_check=("${child_pids[#]}")
child_pids=()
for ((i=0;$i<${#to_check};i++)); do
check_pid ${to_check[$i]}
done
}
function run_command
{
"$#" &
pid=$!
# check this pid now (this will add to the child_pids list if still running)
check_pid $pid
}
# run check on all pids anytime some child exits
trap 'check_done' CHLD
# test
for ((tl=0;tl<10;tl++)); do
run_command bash -c "echo FAIL; sleep 1; exit 1;"
run_command bash -c "echo OKAY;"
done
# wait for all children to be done
wait
Note that this isn't what I ultimately want, but would be groundwork to getting what I want.
Followup: I've implemented a system to do this in Python. So anybody using Python for scripting can have the above functionality. Refer to shelljob
GNU Parallel is awesomesauce:
$ parallel -j2 < commands.txt
$ echo $?
It will set the exit status to the number of commands that failed. If you have more than 253 commands, check out --joblog. If you don't know all the commands up front, check out --bg.
Can I persuade you to use make? This has the advantage that you can tell it how many commands to run in parallel (modify the -j number)
echo -e ".PHONY: c1 c2 c3 c4\nall: c1 c2 c3 c4\nc1:\n\tsleep 2; echo c1\nc2:\n\tsleep 2; echo c2\nc3:\n\tsleep 2; echo c3\nc4:\n\tsleep 2; echo c4" | make -f - -j2
Stick it in a Makefile and it will be much more readable
.PHONY: c1 c2 c3 c4
all: c1 c2 c3 c4
c1:
sleep 2; echo c1
c2:
sleep 2; echo c2
c3:
sleep 2; echo c3
c4:
sleep 2; echo c4
Beware, those are not spaces at the beginning of the lines, they're a TAB, so a cut and paste won't work here.
Put an "#" infront of each command if you don't the command echoed. e.g.:
#sleep 2; echo c1
This would stop on the first command that failed. If you need a count of the failures you'd need to engineer that in the makefile somehow. Perhaps something like
command || echo F >> failed
Then check the length of failed.
The problem you have is that you cannot wait for one of multiple background processes to complete. If you observe job status (using jobs) then finished background jobs are removed from the job list. You need another mechanism to determine whether a background job has finished.
The following example uses starts to background processes (sleeps). It then loops using ps to see if they are still running. If not it uses wait to gather the exit code and starts a new background process.
#!/bin/bash
sleep 3 &
pid1=$!
sleep 6 &
pid2=$!
while ( true ) do
running1=`ps -p $pid1 --no-headers | wc -l`
if [ $running1 == 0 ]
then
wait $pid1
echo process 1 finished with exit code $?
sleep 3 &
pid1=$!
else
echo process 1 running
fi
running2=`ps -p $pid2 --no-headers | wc -l`
if [ $running2 == 0 ]
then
wait $pid2
echo process 2 finished with exit code $?
sleep 6 &
pid2=$!
else
echo process 2 running
fi
sleep 1
done
Edit: Using SIGCHLD (without polling):
#!/bin/bash
set -bm
trap 'ChildFinished' SIGCHLD
function ChildFinished() {
running1=`ps -p $pid1 --no-headers | wc -l`
if [ $running1 == 0 ]
then
wait $pid1
echo process 1 finished with exit code $?
sleep 3 &
pid1=$!
else
echo process 1 running
fi
running2=`ps -p $pid2 --no-headers | wc -l`
if [ $running2 == 0 ]
then
wait $pid2
echo process 2 finished with exit code $?
sleep 6 &
pid2=$!
else
echo process 2 running
fi
sleep 1
}
sleep 3 &
pid1=$!
sleep 6 &
pid2=$!
sleep 1000d
I think the following example answers some of your questions, I am looking into the rest of question
(cat list1 list2 list3 | sort | uniq > list123) &
(cat list4 list5 list6 | sort | uniq > list456) &
from:
Running parallel processes in subshells
There is another package for debian systems named xjobs.
You might want to check it out:
http://packages.debian.org/wheezy/xjobs
If you cannot install parallel for some reason this will work in plain shell or bash
# String to detect failure in subprocess
FAIL_STR=failed_cmd
result=$(
(false || echo ${FAIL_STR}1) &
(true || echo ${FAIL_STR}2) &
(false || echo ${FAIL_STR}3)
)
wait
if [[ ${result} == *"$FAIL_STR"* ]]; then
failure=`echo ${result} | grep -E -o "$FAIL_STR[^[:space:]]+"`
echo The following commands failed:
echo "${failure}"
echo See above output of these commands for details.
exit 1
fi
Where true & false are placeholders for your commands. You can also echo $? along with the FAIL_STR to get the command status.
Yet another bash only example for your interest. Of course, prefer the use of GNU parallel, which will offer much more features out of the box.
This solution involve tmp file output creation for collecting of job status.
We use /tmp/${$}_ as temporary file prefix $$ is the actual parent process number and it is the same for all the script execution.
First, the loop for starting parallel job by batch. The batch size is set using max_parrallel_connection. try_connect_DB() is a slow bash function in the same file. Here we collect stdout + stderr 2>&1 for failure diagnostic.
nb_project=$(echo "$projects" | wc -w)
i=0
parrallel_connection=0
max_parrallel_connection=10
for p in $projects
do
i=$((i+1))
parrallel_connection=$((parrallel_connection+1))
try_connect_DB $p "$USERNAME" "$pass" > /tmp/${$}_${p}.out 2>&1 &
if [[ $parrallel_connection -ge $max_parrallel_connection ]]
then
echo -n " ... ($i/$nb_project)"
wait
parrallel_connection=0
fi
done
if [[ $nb_project -gt $max_parrallel_connection ]]
then
# final new line
echo
fi
# wait for all remaining jobs
wait
After run all jobs is finished review all results:
SQL_connection_failed is our convention of error, outputed by try_connect_DB() you may filter job success or failure the way that most suite your need.
Here we decided to only output failed results in order to reduce the amount of output on large sized jobs. Especially if most of them, or all, passed successfully.
# displaying result that failed
file_with_failure=$(grep -l SQL_connection_failed /tmp/${$}_*.out)
if [[ -n $file_with_failure ]]
then
nb_failed=$(wc -l <<< "$file_with_failure")
# we will collect DB name from our output file naming convention, for post treatment
db_names=""
echo "=========== failed connections : $nb_failed/$nb_project"
for failure in $file_with_failure
do
echo "============ $failure"
cat $failure
db_names+=" $(basename $failure | sed -e 's/^[0-9]\+_\([^.]\+\)\.out/\1/')"
done
echo "$db_names"
ret=1
else
echo "all tests passed"
ret=0
fi
# temporary files cleanup, could be kept is case of error, adapt to suit your needs.
rm /tmp/${$}_*.out
exit $ret

Resources