How do I execute SQL in a loop within a bash script? - sql

I've got a problem with a bash script in which I'd like to execute SQL.
As an example if I simply write :
sqlplus -s << EOF
${USER}/${PASSWD}#DataBase
show user;
exit;
it works.
But as soon as I put it into a loop it doesn't work anymore.
For example :
while (condition)
do
echo $ANSWER
read -p '[y/n]' ANSWER
echo $ANSWER
if [ $ANSWER = 'y' ]
then
sqlplus -s << EOF
${USER}/${PASSWD}#DataBase
show user;
exit;
EOF
break
elif [ $ANSWER = 'n' ]
then
break
fi
done
echo $ANSWER
And the results I've got is : line 26: syntax error : unexpected end of file
(knowing that the line "echo $ANSWER" is the line 25...)
If anyone has an idea about why it doesn't want to work I will be really thankful for the help !

Your problem is that the shell expects the delimiter for the here document at the beginning of the line.
Your EOF is in the middle of the line, and therefore it isn't recognized as a delimiter anymore.
This works as expected:
while (true)
do
echo $ANSWER
read -p '[y/n]' ANSWER
echo $ANSWER
if [ $ANSWER = 'y' ]
then
sqlplus -s << EOF
${USER}/${PASSWD}#DataBase
show user;
exit;
EOF
break
elif [ $ANSWER = 'n' ]
then
break
fi
done
echo $ANSWER

Related

Calling gammu or gammu-smsd-inject

I have gammu-smsd up and running on a raspberry-pi with jessie. I am using runonreceive to process incoming texts. I have the following script working using runonreceive. In the script I am calling gammu sendsms instead of gammu-smsd-inject as the documentation states. All other references state gammu will not work while gammu-smsd daemon is running. The only reason I got this to work is after pulling my hair out trying to get gammu-smsd-inject to work. Can anyone explain what is going on?
RunOnReceive = /home/jaalfs/bin/sms_back.sh
sms_back.sh
#!/bin/bash
from=$SMS_1_NUMBER
echo "sms_back" >> /home/jaalfs/bin/sms_back.log
echo "Test from: $from" >> /home/jaalfs/bin/sms_back.log
echo -e "\n"
if [ "$from" != "+1310xxxxxxx" ]; then
echo -e "not accepted number \n" >> /home/jaalfs/bin/sms_back.log
exit 0
else
echo "accepted number" >> /home/jaalfs/bin/sms_back.log
echo "hello world!!!!!!" | sudo gammu sendsms TEXT "$from"
echo -e " text sent back \n" >> /home/jaalfs/bin/sms_back.log
exit 0
fi
exit 1

String comparison in ksh never succeeding

I have the next script, and when trying to compare variable value if equals "NO" or "SI" (yes in spanish) it's not working for some reason I keep going all the time through the else (SI) although the real value in the variable is "NO". It's even being printed in the email subject.
I fear I could be some extra invisible character I can't see but it's there?
Here is the script:
#!/usr/bin/ksh
VAR=$(/home/userName/scripts/loadedresource.ksh | egrep 'SI|NO')
MAIL_FILE="testfile.txt"
rm -f $MAIL_FILE
echo "From:Script" > $MAIL_FILE
echo "To:Me<me#company.com>" >> $MAIL_FILE
echo "Subject:RESOURCE LOADED-> $VAR" >> $MAIL_FILE
echo "Content-Type: text/html" >> $MAIL_FILE
echo "<html>" >> $MAIL_FILE
echo "<body style='font-family:calibri;font-size:14px;'>" >> $MAIL_FILE
if [ "$VAR" == "NO" ]
then
echo "<h2> Resource not loaded, please open ticket </h2>" >> $MAIL_FILE
else
echo "<h2> Resource loaded successfully </h2>" >> $MAIL_FILE
fi
mail me#company.com < $MAIL_FILE
== is not a valid comparison operator in POSIX test. If your particular implementation of ksh doesn't implement an extension adding it, you may need to use
if [ "$VAR" = "NO" ]
rather than
if [ "$VAR" == "NO" ]
I'd also consider using egrep -o 'SI|NO' to leave out any other characters from the output of grep, if your copy has GNU extensions.
As another option, consider:
result=$(/home/userName/scripts/loadedresource.ksh)
case $result in
*SI*) echo "Yes" ;;
*NO*) echo "No" ;;
*) echo "Unknown" ;;
esac
As a performance enhancement, by the way:
{
echo "hello"
echo "world"
} >output.txt
...is considerably more efficient than
echo "hello" >output.txt
echo "world" >>output.txt
...which re-opens the output file once for each line.

Ignore ORA-28011 in sqlplus in bash script

I am using sqlplus in a shell script and I am using WHENEVER SQLERROR EXIT 8 and WHENEVER OSERROR EXIT 9 so that I can catch errors using $?.
I will be putting this code on a server that I know gets the password expiry warning/error 'ORA-28011'.
My question is, will my script catch on 'ORA-28011' even though it isn't really an error? If so, how would I go about ignoring it?
My (simplified) code, if it helps:
[...]
CONNECTION_STRING=$USER/$PASS#$TNS
RESULT=$(sqlplus -s /nolog <<-EOF
WHENEVER OSERROR EXIT 9;
WHENEVER SQLERROR EXIT 8;
$OPTIONS
CONNECT $CONNECTION_STRING
$DB_SQL
COMMIT;
EOF)
RETURN_CODE=$?
echo "db_exec: Result -> $RETURN_CODE\n$RESULT"
if [ $RETURN_CODE -eq 0 ]
then
echo "$RESULT"
return 0
else
echo "db_exec: Failed"
return 1
fi
In case anyone is interested, I solved this problem.
ORA-28011 and ORA-28002 do not cause SQL*Plus to exit when using WHENEVER SQLERROR EXIT # or WHENEVER OSERROR EXIT # but will appear in the result. Therefore the code in my question will work, but I need to remove these errors. My updated code is below:
# Run the SQL with the options specified
RESULT=$(sqlplus -s /nolog <<-EOF
WHENEVER SQLERROR EXIT 4;
WHENEVER OSERROR EXIT 5;
SPOOL $TEMP_FILE;
$DB_OPTIONS
$DB_CONNECT
$DB_SQL
COMMIT;
EOF)
# Save the return code
RETURN_CODE=$?
# Log the result
echo "Result -> Code: $RETURN_CODE\n$RESULT" 1>&2
if [ $( grep -cE '^ORA-28002:|^ORA-28011:' $TEMP_FILE) -ge 1 ]
then
echo "Warning -> Password Expiry \n$(grep '^ORA-' $TEMP_FILE)" 1>&2
fi
# Check the return code and catch any SQL*Plus (SP2-) errors that might not have presented an error code
if [ $RETURN_CODE -eq 0 ] && [ $(grep -c '^SP2-[0-9][0-9][0-9][0-9]' $TEMP_FILE) -eq 0 ]
then
# Echo the result, but remove any lines regarding password expiry
echo "$RESULT" | grep -v "^ERROR:" | grep -v "^ORA-[0-9][0-9][0-9][0-9][0-9]"
rm $TEMP_FILE
echo "Success" 1>&2
return 0
elif [ $RETURN_CODE -eq 4 ]
then
echo "Failed -> SQL Error \n$(grep '^ORA-' $TEMP_FILE) $(grep '^SP2-' $TEMP_FILE)" 1>&2
return 4
elif [ $RETURN_CODE -eq 5 ]
then
echo "Failed -> OS Error \n$(grep '^ORA-' $TEMP_FILE) $(grep '^SP2-' $TEMP_FILE)" 1>&2
return 5
elif [ $(grep -c "^SP2-[0-9][0-9][0-9][0-9]" $TEMP_FILE) -ne 0 ]
then
echo "Failed -> SQL*Plus Error \n$(grep '^SP2-' $TEMP_FILE)" 1>&2
return 6
else
echo "Unknown error -> $RETURN_CODE\n$RESULT" 1>&2
return 3
fi

bash check value is integer and in range

I read this stackoverflow question...
Bash: check user input is correct
which does most of what I want however rather then checking it's just an integer I need to check it's an integer in a variable range....
The script looks for files in a directory and then assigns a number to them...
File 1
File 2
File 3
etc....
The user chooses the the number and the script then executes commands against that file.....the variable $FILELIST is the total number of files.
Taking the example from the previous stackoverflow I tried.....
FILENUM=""
while [[ ! ($FILENUM =~ ^[0-$FILELIST]+$) ]]; do
echo " "
echo "Please enter the file number: "
read -p "1 - $FILELIST" FILENUM < /dev/tty
done
echo "$FILENUM"
However this is throwing a syntax error: unexpected "(" (expecting "do") in the while line and I'm not sure why, I suspect $FILELIST has to be bracketed somehow but an explanation as to why the above works would help me understand the problem.
Thanks
bash-specific answers:
You don't need to reinvent the wheel: use the select builtin:
cd /path/to/directory
PS3="Select a file: "
select file in *; do
if [[ $file ]]; then break; fi
done
echo "You selected '$file'"
echo "You selected file number $REPLY"
To check a number is within a certain range, I'd write:
if (( 0 <= $number && $number <= $max )); then echo "in range"; fi
Since you're using ash you might use this as a reference: http://manpages.debian.net/cgi-bin/man.cgi?query=dash
while true; do
FILENUM=""
echo
echo "Please enter the file number: "
read -p "1 - $FILELIST" FILENUM < /dev/tty
if expr "$FILENUM" : '[0-9]\+$' &&
[ $FILENUM -gt 0 ] &&
[ $FILENUM -le $FILELIST ]
then
break
fi
done
echo "$FILENUM"

Match pattern for variable in Shell Programming

it seems that I keep getting -gt or == error with the following. Can someone help?
flag= echo $flightSeatBooked | awk -F[,] '{print match($flightSeatBooked, $orderSeats)}'
if $flag == 0; then
echo "Success";
else
echo "fail";
Given:
flightSeatBooked= 9;,A1,A2,A3,A4,B2,E4,C3,B3,D3,D2,E1,E2,C2,B4,C4,D4,C1,D1,E3,B1
orderSeats= B2 (not found in the variable)
Expected output:
Success
Quite a few mistakes. Change it like this:
flag=$(echo $flightSeatBooked | awk -v flseat=$flightSeatBooked -v orseat=$orderSeats '{print match(flseat, orseat)}')
if [ $flag -eq 0 ]; then
echo "Success";
else
echo "fail";
fi
Command substitution has been done using the $(...) notation.
It is not a good practice to use the shell variables directly in awk, and hence passed shell variables to awk using -v.
The syntax of if used was incorrect, updated to correct it.
This is how to do what you ask:
flag=$(awk -v flseat="$flightSeatBooked" -v orseat="$orderSeats" 'BEGIN{print index(flseat, orseat)}')
if [ $flag -eq 0 ]; then
echo "Success"
else
echo "fail"
fi
BUT I don't think what you ask is a good idea. It at least should be something like this:
awk -v flseat="$flightSeatBooked" -v orseat="$orderSeats" 'BEGIN{exit index(flseat, orseat)}')
if [ $? -eq 0 ]; then
echo "Success"
else
echo "fail"
fi
and all you probably really need is something like this:
case "$flightSeatBooked" in
*"$orderSeats"* ) echo "fail";;
* ) echo "Success" ;;
esac
Check the logic (as I haven't!), but hopefully you get the approach.
You can also use this below to check whether $orderSeats is in $flightSeatBooked. If it is in then it return the length of string that matched or 0 is returned.
expr "$flightSeatBooked" : ".*,${orderSeats},"