In this script, I'm trying to get the result of a SQL query into a variable count which I later compare to determine whether to send email.
When I execute the script, I get an integer expression expected error.
This is is my script.
LOGFILE=/home/ni916c/${SCRIPT}.$RUN_DATE.log
RPTNAME=/home/ni916c/ASPEN_LOADER_error.xls
#rm $LOGFILE
count=$(sqlplus -S ni916c/rajabeta17 <<-EOF
set heading off
SET FEEDBACK OFF
SELECT 'Loader File Failed:: '||to_char(load_id) ||' '|| to_char(file_id) ||' '||file_name||' '||to_char(load_status_id) FROM DL_FILES_RECEIVED
WHERE
period_id = to_number(to_char(sysdate,'yyyymm'))
and load_status_id=300;
-- in (select load_status_id from DL_LOAD_STATUS where category like '%ERROR%');
exit;
EOF
)
echo "$count" >> $LOGFILE
if [ "$count" -ne 0 ]
then
mailx -s "LOADER ERROR" rk862h#att.com < $LOGFILE
fi
I assume the error comes from one of two sources :
There is a problem in your SQL statement (in which case you should try to debug it outside of the script)
It is if [ "$count" -ne 0 ] that fails, because your statement does not return an integer.
If the problem is (2) above, you may have to add some kind of error handling to your script to detect unexpected results. For instance :
if
[[ "$count" =~ ^[0-9]+$ ]]
then
# Ok, we have an integer
else
# Oops, something went wrong
fi
You should also make sure that the SQL statement is not returning additional characters that cause the count variable not to be recognized as an integer, in which case some trimming might be required.
result=$(psql -U "$user" -h "$host" -p "$port" -d "$main_schema" -c "select object_version from db_utility.versions" 2>&1)
This is the way to get result of postgresql query in bash variable
Related
I'm trying to run a shell command (currently either sh or bash) which connects to a database. Because the database is still 'warming up', the command fails.
So I was trying to do a loop (let's say ... 100 tries) and each time the command fails, wait 1 second and retry.
If there's an error, this is the start of the string that is dumped to stdout: Sqlcmd: Error: <snipped>
Here's what I've been trying:
for i in $(seq 1 100)
do
X='/opt/mssql-tools/bin/sqlcmd -E -S localhost -Q "<some sql statement> "'
if [[ $X == Sqlcmd: Error:* ]]
echo "."
then
break
fi
done
It's not working as I figure out the string comparison stuff with shell/bash ... but was more making sure if I was on the right track etc.
You could try something like:
while true ; do
if Sqlcmd xxx xxx xxx ; then break ; fi
# or:
Sqlcmd xx xxx xxx && break
sleep 1
done
You can also add a counter:
for ((n=100;n>0;n--)) ; do
Sqlcmd xxx xxx xxx
if [[ $? == 0 ]] ; then
break
fi
sleep 1
done
[[ $n == 0 ]] && echo Timeout && exit 1
I'm showing two different ways of testing the return value here, but the first one is preferred (if cmd ; then ... ; fi).
$? is the return value from the last command, which is 0 when it completed successfully. If it returns 0 even in case of error (which can happen for malformed programs), you can test the output with grep:
Sqlcmd xxx xxx 2>&1 | grep <error pattern> > /dev/null
if [[ $? != 0 ]] ; then break ; fi
Here we test $? != 0 because grep will return 0 when the error pattern has been found.
If you want to get the output result into a variable, run the command with X=$(Sqlcmd xxx xxx). Then you can use bash string comparison:
X=$(Sqlcmd xxx xxx)
if [[ "$X" =~ .*error.* ]] ; then
<handle error here>
fi
Note bash can match regexp, which makes it really handy at checking error types.
You can also use a switch/case construct:
case "$X" in
*Error:*) echo " Error detected " ;;
*) break ;;
esac
(Note the double ;;)
I ended up learning all the clues from #matthieu's post. This is what I ended up doing:
for i in $(seq 1 30)
do
/opt/mssql-tools/bin/sqlcmd -U sa -P <snip> -S localhost -Q "USE Master" 2>&1
if [[ $? != 0 ]]
then
# Failed
echo "."
sleep 1s
else
# worked!
break
fi
done
breakdown for those learning (like me)
execute a sql query using the sqlcmd command. Any errors via stderr (that's the 2 in 2>&1) will be redirected to the console stdout (that's the $1). REF: 2>&1 shell idiom.
the result status code is sent to $? (REF: what is bash dollar questionmark ?)
if it failed(any value that is NOT a zero), then sleep 1 sec and we'll try. Only re-try 30 times, though.
if we worked (value is zero), then stop trying and go on....
So there we have it! shell/bash shell 101 stuff. good luck!
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
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
Script:
while read -r records
do
sErrors=`sqlplus /<<EOF
WHENEVER SQLERROR EXIT SQL.SQLCODE;
select id from table where name='"$records"';
#if select succeeds then update
update table set name='xyz';
exit;
EOF`
if [[ $sErrors = "ORAsomenumber" ]]
then
echo "Failed for $records with error:$sErrors">>logfile.log
fi
done<file
I need to trap any error specific to select query(i.e. "NO DATA FOUND") or any
Database specific error that might occur for a record in a while loop and continue
without exit till the end of reading all records
Oracle version : 10.2.0.5.0
Note: it is not mandatory to get specific ORA error only, any hint indicating the specific db error would be enough
Thanks.
file:
name1 newname1
name2 newname2
name3 newname3
script:
#!/bin/sh
#set var
export ORACLE_HOME=/oracle/product/db_1/
export ORACLE_SID=orcl
export PATH=$ORACLE_HOME/bin:$PATH
ora_user="user"
ora_pwd="password"
ora_tns="dbtnsname"
log_file=/var/log/sql.log
while read user newname
do
sqlplus -S $ora_user/$ora_pwd#$ora_tns <<EOF >>$log_file
SET SERVEROUTPUT ON
DECLARE V_ID INT DEFAULT 0;
BEGIN
SELECT ID INTO V_ID FROM TABLE WHERE NAME = "$user";
IF V_ID = 0 OR V_ID IS NULL
THEN
DBMS_OUTPUT.PUT_LINE("FAILED FOR $user WITH ERROR:NOT DATA FOUND");
ELSE
UPDATE TABLE SET NAME="$newname" WHERE NAME = "$user";
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE("FAILED FOR $USER WITH ERROR:"||SQLERRM);
END;
/
EOF #must top grid
done<file
The way the sqlplus invoked is fine in your script, But string comparison does not work as it contains the whole error if you want to check for some particular error code (or) only some part of the string, Use grep command.
echo $sErrors | grep "ORA-ERROR1" && echo "ORA-ERROR1 Found"
echo $sErrors | grep "ORA-ERROR2" && echo "ORA-ERROR2 Found"
In the above case, it prints both grep output and the echo command output if it matches.
If you don't want the output to be printed, You can follow the below.
echo $sErrors | grep "ORA-ERROR1" > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "ORA-ERROR1 Found"
fi
I have been busy this week trying to wrap my head around a little Bash program to migrate a CMS from one server to another. The reasopn for this is because I have more tha 40 of these to do, and need to get it done in a timely manner, thus the Bash idea.
Needless to say, I have run into a couple of problems so far, but one of them has halted my development completetly, directory checking.
No I have tried a couple of methods and none of them seem to work really. The catch is that I have to check the folder on a remote server via ssh. Here my example:
ExSshRsa=~/.ssh/id_rsa
ExSshPort=22
ExSshHost=localhost
ExRoot=/var/www/
echo -n "Verifying Root access $ExRoot..."
SSHRoot='ssh -i $ExSshRsa -p $ExSshPort $ExSshHost [ -d $ExRoot ] || exit 1 '
echo $SSHRoot
if [ "$SSHRoot" -eq 0 ]
then
echo "OK"
else
echo "FAIL"
fi
I get the Error: [: : integer expression expected
Does the [ or test not resturn a 0 which is numerical. ?
Passing strings as arguments to a remote host is not trivial; you need to use arrays. A test example:
declare -a cmd=(touch "file name with spaces")
printf -v escaped_cmd_str '%q ' "${cmd[#]}"
ssh localhost $escaped_cmd
ssh localhost ls # Should return "file name with spaces" on a separate line
So your case should be:
ExSshRsa=~/.ssh/id_rsa
ExSshPort=22
ExSshHost=localhost
ExRoot=/var/www/
echo -n "Verifying Root access $ExRoot..."
declare -a cmd=( '[' -d "$ExRoot" ']' ) # Need to quote "[" since it's a Bash-specific symbol
printf -v escaped_cmd_str '%q ' "${cmd[#]}"
if ssh -i "$ExSshRsa" -p "$ExSshPort" "$ExSshHost" $escaped_cmd
then
echo "OK"
else
echo "FAIL"
fi
This is a rare case where using unquoted variable expansion is perfectly fine.
change the shebang to #!/bin/bash -x and look at the output...
you are storing a string in variable SSHRoot using single quotes, meaning that no variables will be expanded, i.e. a $ is still a $. Use double quotes instead, i.e. "
to store the output from a command in bash, use
var=$(cmd)
the exist status of a command is stored in the variable $?. Do a check on that after the ssh-command
you are never executing the ssh-command in your code
Great link here for bash-programming
Try the following:
ExSshRsa=~/.ssh/id_rsa
ExSshPort=22
ExSshHost=localhost
ExRoot=/var/www/
echo -n "Verifying Root access $ExRoot..."
cmd="bash -c \"[ -d $ExRoot ] || exit 1\""
SSHRoot="ssh -i $ExSshRsa -p $ExSshPort $ExSshHost ${cmd}"
$SSHRoot
if [ $? -eq 0 ]
then
echo "OK"
else
echo "FAIL"
fi
The variables weren't being replaced in your SSHRoot variable as it's in single quotes. Also, you weren't passing an executable command, so that's why I use bash -c above. It will run the bash commands inside the quoted string.
$? stores the exit value of the last command, in this case the SSHRoot one.
#!/bin/bash
ExSshRsa=~/.ssh/id_rsa
ExSshPort=22
ExSshHost=localhost
ExBase='/tmp/'
ExRoot='one space/'
declare -a AExRoot
for argR in "${ExRoot[#]}"
do
ExRoot+=($(printf %q "$argR"))
done
clear
FRoot=( $ExBase${ExRoot[#]} )
echo -n "Verifying Root access $FRoot..."
SSHRootTest="bash -c \"[ -d $FRoot ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHRoot=$( ssh -i $ExSshRsa -p $ExSshPort $ExSshHost ${SSHRootTest})
if [ $? -eq 0 ]
then
echo -en "\e[1;32mOK\e[0;37;m..."
else
echo -en "\e[1;31mFAIL\e[0;37;m..."
fi
sleep 1
if [ -w $FRoot ]
then
echo -e "\e[1;32mwritable\e[0;37;m"
else
echo -e "\e[1;31mNOT writeable\e[0;37;m"
fi
echo -e "\e[0;m"
exit 0
So I have incorporated all of the suggestions so far and have one last problem, the FRoot is not getting populated by the complete array values. Other than that I think it now has the subjective approach as suggested #john-keyes, the proper expansion #frederik and the crazy space escapes #l0b0