How to do sqlplus in bash if else? - linux

I am trying to write a bash function which should delete some entries from table1 if the user enters 1, otherwise remove different entries. My function looks like this:
function reset_db
{
if [ $usr_input == 1 ]
then
sqlplus -s $USR/$pwd#$SID << EOF
delete from table1 where component = 'ABC';
delete from table2 where component = 'ABC';
exit
EOF
else if [ $usr_input == 2 ]
delete from table1 where component = 'XYZ';
delete from table2 where component = 'XYZ';
exit
EOF
fi
}
I am getting error: syntax error near unexpected token `fi'
I am sure that it is happening because I am using if-else incorrectly somewhere but not able to figure out a way to fix it.
Also please let me know how can I post code under the same thread if I have any more follow up questions.

Your 'else if' is wrong, the correct syntax is 'elif'.

You need to repeat the command in each clause of the if statement:
function reset_db
{
if [ $usr_input == 1 ]
then
sqlplus -s $USR/$pwd#$SID << EOF
delete from table1 where component = 'ABC';
delete from table2 where component = 'ABC';
exit
EOF
elif [ $usr_input == 2 ]; then
sqlplus -s $USR/$pwd#$SID << EOF
delete from table1 where component = 'XYZ';
delete from table2 where component = 'XYZ';
exit
EOF
fi
}
As a simplification, you should refactor this:
reset_db () {
if [[ $usr_input = 1 ]]; then
to_delete='ABC'
elif [[ $usr_input = 2 ]]; then
to_delete='XYZ'
else
return
fi
sqlplus -s "$USR/$pwd#$SID" <<EOF
delete from table1 where component = '$to_delete'
delete from table2 where component = '$to_delete'
exit
EOF
fi
}

Related

How to pass parameters from Perl script to SQL script and execute it from Perl script?

I use Informix as database in Linux environment.
I have a Perl script which should execute an SQL-script. Before execution, it should also pass all parameters to the SQL-script.
I can't figure out how to pass parameters to .sql script?
It also does run but I get following error.
DBD::Informix::st fetchrow_array failed: SQL: -400: Fetch attempted on unopen cursor. at startSelectQuer.pl
How can I realize this?
selectQuer.sql
DROP TABLE IF EXISTS tempTable;
SELECT * FROM 'informix'.systables INTO TEMP tempTable;
DROP TABLE IF EXISTS magic_ant;
select * from del_new
where
id = $i_id and
year = $i_year and
month = $i_month
into
temp magic_ant;
DROP TABLE IF EXISTS magic_buck;
select * from upper_new
where
id = $i_id and
year = $i_year and
month = $i_month
into
temp magic_buck;
DROP TABLE IF EXISTS alleMagic;
select * from magic_ant
union
select * from magic_buck
into temp alleMagic;
select lname, fname, ext from alleMagic;
startSelectQuer.pl
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
my ($ID) = $_[0];
my ($YEAR) = $_[1];
my ($MONTH) = $_[2];
my $BEG_ANT=801 ;
my $END_ANT=803 ;
my $BEG_BRU=802 ;
my $END_BRU=900 ;
my($dbh, $sth, $query);
######################################################################
my $database = "$ENV{DBNAME}";
my $user ="";
my $pass ="";
$dbh = DBI->connect("dbi:Informix:$database", $user, $pass);
######################################################################
die "failed to connect to MySQL database:DBI->errstr()" unless($dbh);
my $sqlFile = "/SQLSCRIPTS/selectQuer.sql";
open (SQL, "$sqlFile") or die("Can't open file $sqlFile for reading");
# Loop though the SQL file and execute each and every one.
while (my $line = <SQL>) {
chomp $line;
$line = join(' ',split(' ',$line));
if ((substr($line,0,2) ne '--') and (substr($line,0,3) ne 'REM')) {
if (substr($line,- 1,1) eq ';') {
$query .= ' ' . substr($line,0,length($line) -1);
# replace with value
replaceQueryWithValue($query);
$sth = $dbh->prepare($query, {'ix_CursorWithHold' => 1})
or die "prepare statement failed: $dbh->errstr()";
$sth->execute() or die "execution failed: $dbh->errstr()";
my $rows = $sth->rows;
#loop through each row of the result set, and print it.
if ($rows > 0) {
# Getting error here as: DBD::Informix::st fetchrow_array failed:
# SQL: -400: Fetch attempted on unopen cursor.
while(my #row = $sth->fetchrow_array) {
print qw($row[0]\t$row[1]\t$row[2]\n);
}
} else
{
print "\nThere is no result for query: $query\n" ;
}
$query = ' ';
} else {
$query .= ' ' . $line;
}
}
}
# close data connection
$sth->finish;
$dbh->disconnect;
sub replaceQueryWithValue{
$query =~ s/i_id/$ID/ig;
$query =~ s/i_year/$YEAR/ig;
$query =~ s/i_month/$MONTH/ig;
}
When asking a question like this, it's useful if you tell us exactly what isn't working as you expect it to. Does nothing happen? Do you get an error message? Does your computer burst into flames?
Without that, we're pretty much guessing. But I'm happy to have a guess here. I know nothing about Informix, but I would guess that you're seeing the "prepare statement failed" error. Is that right?
If so, it seems to be that you're trying to compile an SQL statement that looks like SQLSCRIPTS/selectQuer.sql - when actually, that is the name of a file that you should be opening and reading your SQL statement from.
I used $sth->fetch instead of $sth->fetchrow_array after execution of .sql as below.
$sth = $dbh->prepare( "select * from alleMagic;" );
$sth->execute;
# Column binding is the most efficient way to fetch data
my $rv = $sth->bind_columns(\$lname, \$fname, \$ext );
while ($sth->fetch) {
print "$lname, $fname, $ext \n";
}

Ignore the 1st row(header) in a csv files using shell script

Following is my csv file
Contact Id,Customer Code,Billing Account Code,Bank BSB,Bank ID
2222222220,2222222222222220,100,084004,fjksanfjkdsksdnfnkjsnQ==
3333333330,3333333333333330,100,084789,sklsnfksnkdfnkgndfkjgn==
and this is the code I'm using to ignore header & any row which has no data in any of 5 columns
while IFS=',' read cont_id cust_code bac bsb bid
do
if [ "$cont_id" == "" ] || [ "$cust_code" == "" ] || [ "$bac" == "" ] || [ "$bsb" == "" ] || [ "$bid" == "" ]; then
echo $cont_id,$cust_code,$bac,$bsb,$bid >> $SOURCE_DIR/dummyRejectedRecords.csv
elif [ "$cont_id" == "Customer Code" ] && [ "$cust_code" == "Customer" ] && [ "$bac" == "Billing Account Code" ] && [ "$bsb" == "Bank BSB" ] &&[ "$bid" == "Bank ID" ]; then
echo $cont_id,$cust_code,$bac,$bsb,$bid >> $SOURCE_DIR/dummyRejectedRecords.csv
else
echo "Contact_Id = '"$cont_id"'"
echo "Customer_Code = '"$cust_code"'"
echo "Billing_Account_Code = '"$bac"'"
echo "Bank_ID = '"$bsb"'"
echo "Bank_BSB = '"$bid"'"
echo ""
#ADD YOUR PROCEDURE HERE
fi
done < $SOURCE_DIR/dummy.csv
The problem is that 1st row is not being ignored
and this is being appended to 1x1 value of csv Customer Code = 'Customer Code'
even if header is ignored the 1st value of next row is appended with 
Could someone help me here (without using awk command)
Thanks a ton in advance
The first thing that comes to mind is to use a simple control variable to skip the first iteration, provided that the file always contains a header that has to be ignored as the first line.
Add this before the first if statement inside the loop:
if [ -z "$HEADER_DONE" ]; then
HEADER_DONE=1
continue
fi

shell scripting - assigning one variable to another - arrays

I have a doubt. When i declare a value and assign to some variable, I don't know how to reassign the same value to another variable. See the code snippet below.
Here is my actual script.
#!/bin/sh
a=AA
b=BB
c=CC
d=DD
e=EE
f=FF
alpha_array=(a b c d e f)
process_array=(proc1 proc2 proc3 proc4)
array_1=("")
array_2=("")
display_array() {
echo "array1 = ${array_1[#]}"
echo "array2 = ${array_2[#]}"
}
checkarg() {
if [[ " ${alpha_array[*]} " == *" $token "* ]]; then
echo "alphabet contains $token "
array_1=("${array_1[#]}" "$token")
$token=${$token}
echo "TOKEN = $token"
elif [[ " ${process_array[*]} " == *" $token "* ]]; then
echo "process contains $token "
array_2=("${array_2[#]}" "$token")
else
echo "no matches found"
display_array
exit 1
fi
}
for token in $#
do
echo $token
checkarg
done
display_array
Here the below two lines
$token=${$token}
echo "TOKEN = $token"
should display my output as
TOKEN = AA
TOKEN = BB
when i run my script with the following arguments.
./build.sh a b proc1
Kindly help me out on those 2 lines.
It sounds like what you want is variable indirection. There's a lot of code in your question which has nothing to do with that, but let me try to distill it down to what I understand as the important parts:
a=AA
b=BB
alpha_array=(a b)
for token in "${alpha_array[#]}"; do
value=${!token}
echo "value of variable $token is $value"
done
When run, this will output:
value of variable a is AA
value of variable b is BB
For more details, see BashFAQ #6.
By the way, this can often be replaced with use of associative arrays, in which case you might write:
declare -A tokens=( [a]=AA [b]=BB )
for token in "${!tokens[#]}"; do
value=${tokens[$token]}
echo "value of token $token is $value"
done
This has the advantage that your key/value pairs are all stored inside the array -- there's no potential for collision with other variable names.

enum data type seems not available in bash

Having bash, created simple scripts for accessing array element by it's index.It as follows
#! /bin/bash
OK_INDEX=0
CANCEL_INDEX=1
ERROR_INDEX=2
CONFIRM_INDEX=3
SAVE_INDEX=4
EXIT_INDEX=5
declare -a messageList=("ok"
"cancel"
"error"
"confirm"
"save"
"exit")
printf "%s \n" ${messageList[$CANCEL_INDEX]}
from above scripts i need to declare proper index variable to retrieve valid message from array list but it likely not handy for me to declare each variable and give index to them.It is nice if variable autometically getting value as like in C for ENUM data type
in C it's possible by like
enum index { OK_INDEX, CANCEL_INDEX, ERROR_INDEX,CONFIRM_INDEX,SAVE_INDEX,EXIT_INDEX};
is there any alternative for ENUM in bash?
I found lot but not succeded then have try some trick to achieve this it is as follows
ENUM=(OK_INDEX CANCEL_INDEX ERROR_INDEX CONFIRM_INDEX SAVE_INDEX EXIT_INDEX)
maxArg=${#ENUM[#]}
for ((i=0; i < $maxArg; i++)); do
name=${ENUM[i]}
declare -r ${name}=$i
done
So form above code snippet i successfully created constant but it seems lengthy means just declaring variable i need to write 5-10 lines code which is not fair.
So any one have another solution?
Try the following fragment of code ... I guess that it is what you want
#!/bin/bash
set -u
DEBUG=1
# This funcion allow to declare enum "types", I guess
enum ()
{
# skip index ???
shift
AA=${###*\{} # get string strip after {
AA=${AA%\}*} # get string strip before }
AA=${AA//,/} # delete commaa
((DEBUG)) && echo $AA
local I=0
for A in $AA ; do
eval "$A=$I"
((I++))
done
}
### Main program
# Just declare enum as you need
enum index { OK_INDEX, CANCEL_INDEX, ERROR_INDEX, CONFIRM_INDEX, SAVE_INDEX, EXIT_INDEX };
# Print value of enumerated items
echo $OK_INDEX
echo $CANCEL_INDEX
echo $ERROR_INDEX
echo $CONFIRM_INDEX
echo $SAVE_INDEX
echo $EXIT_INDEX
# Use enumerated index in program
I=CONFIRM_INDEX
case $I in
OK_INDEX )
echo "Process here when index is $I"
;;
CANCEL_INDEX )
echo "Process here when index is $I"
;;
ERROR_INDEX )
echo "Process here when index is $I"
;;
CONFIRM_INDEX )
echo "Process here when index is $I"
;;
SAVE_INDEX )
echo "Process here when index is $I"
;;
EXIT_INDEX )
echo "Process here when index is $I"
;;
esac
exit 0
My take on this:
function \
_enum()
{
## void
## (
## _IN $# : [ array<string> ] list
## )
local list=("$#")
local len=${#list[#]}
for (( i=0; i < $len; i++ )); do
eval "${list[i]}=$i"
done
}
Example:
ENUM=(
OK_INDEX
CANCEL_INDEX
ERROR_INDEX
CONFIRM_INDEX
SAVE_INDEX
EXIT_INDEX
) && _enum "${ENUM[#]}"
echo "OK_INDEX = "$OK_INDEX
echo "CANCEL_INDEX = "$CANCEL_INDEX
echo "ERROR_INDEX = "$ERROR_INDEX
echo "CONFIRM_INDEX = "$CONFIRM_INDEX
echo "SAVE_INDEX = "$SAVE_INDEX
echo "EXIT_INDEX = "$EXIT_INDEX
Output
OK_INDEX = 0
CANCEL_INDEX = 1
ERROR_INDEX = 2
CONFIRM_INDEX = 3
SAVE_INDEX = 4
EXIT_INDEX = 5
I find this to be the cleanest and most straightforward approach.
Another solution is to assign values to an associative array to make an enum set with the variable name as the prefix. This allows introspection of the enum by walking through all available values and their associated key names:
function \
_enum_set()
{
## void
## (
## _IN $1 : [ string ] prefix
## _IN ... : [ array<string> ] list
## )
local prefix=$1
local list=("$#")
local len=${#list[#]}
declare -g -A $prefix
for (( i=0; i < $len; i++ )); do
# Skip the first argument
[[ $i = 0 ]] &&
continue
eval "$prefix[${list[$i]}]=$(( $i - 1 ))"
done
}
Example (looping):
ENUM=(
OK
CANCEL
ERROR
CONFIRM
SAVE
EXIT
) && _enum_set ENUM_INDEX "${ENUM[#]}"
echo ""
for i in "${!ENUM_INDEX[#]}"; do
echo "ENUM_INDEX[$i] = "${ENUM_INDEX[$i]}
done
Output:
ENUM_INDEX[CONFIRM] = 3
ENUM_INDEX[OK] = 0
ENUM_INDEX[EXIT] = 5
ENUM_INDEX[ERROR] = 2
ENUM_INDEX[SAVE] = 4
ENUM_INDEX[CANCEL] = 1
Example (explicit):
ENUM=(
OK
CANCEL
ERROR
CONFIRM
SAVE
EXIT
) && _enum_set ENUM_INDEX "${ENUM[#]}"
echo "ENUM_INDEX[OK] = "${ENUM_INDEX[OK]}
echo "ENUM_INDEX[CANCEL] = "${ENUM_INDEX[CANCEL]}
echo "ENUM_INDEX[ERROR] = "${ENUM_INDEX[ERROR]}
echo "ENUM_INDEX[CONFIRM] = "${ENUM_INDEX[CONFIRM]}
echo "ENUM_INDEX[SAVE] = "${ENUM_INDEX[SAVE]}
echo "ENUM_INDEX[EXIT] = "${ENUM_INDEX[EXIT]}
Output:
ENUM_INDEX[OK] = 0
ENUM_INDEX[CANCEL] = 1
ENUM_INDEX[ERROR] = 2
ENUM_INDEX[CONFIRM] = 3
ENUM_INDEX[SAVE] = 4
ENUM_INDEX[EXIT] = 5
Note that associative arrays have no defined order but can always be sorted at a later point.
You can consolidate some of the lines:
$ for i in \
E_OK E_CANCEL E_ERROR E_CONFIRM E_SAVE E_EXIT; do \
readonly ${i}=$((x++)); done
$ for i in ${!E_#}; do echo $i=${!i}; done
Another version using mapfile callback function:
#!/bin/bash
mapfile -t -c 1 -C 'f(){ readonly $2=$1; }; f' << \
EOF
E_OK
E_CANCEL
E_ERROR
E_CONFIRM
E_SAVE
E_EXIT
EOF
for i in ${!E_#}; do echo $i=${!i}; done
Output:
E_CANCEL=1
E_CONFIRM=3
E_ERROR=2
E_EXIT=5
E_OK=0
E_SAVE=4
The typical workaround when an enum is wanted is to use normal strings. In these cases I even omit the otherwise mandatory quotes around variable evaluation:
state=IDLE
...
while [ $state = IDLE ]
do
...
if condition
then
state=BUSY
fi
...
if condition2
then
state=ERROR
fi
...
done
if [ $state = ERROR ]
then
...
fi
This way, of course, you have just the basic functionality of named states and neither of the following typically associated features of enums:
declaration of all possible values (self-documenting code)
associated number for each value (matter of taste if this is a feature or a wart)
no prevention/detection of mistypings (but this is rare in scripts anyway)

Calling two functions one after other is failing in bash/sqlplus

I have two functions- ABC, XYZ. ABC deletes some rows in table1 as user1 and XYZ drops some users as DB User. First I am calling ABC and then XYZ. ABC function is being executed but at XYZ it is failing- "XYZ: command not found"
function ABC
{
sqlplus -s $ur1/$pwd#$SID << EOF
delete from table1 where row_name = 'A1';
delete from table2 where row_name = 'A2';
exit
EOF
}
function XYZ
{
sqlplus eip_dba/eip_dba$result#${input} << eof
set timing off
set serveroutput on size 10000
set feedback off
spool xyz_$input.out
drop user usr1 cascade;
drop user usr2 cascade;
drop user usr3 cascade;
commit;
exit
eof
}
ABC
XYZ
bash-3.2$ ./db_test.sh
2 rows deleted.
2 rows deleted.
./db_test.sh: line 100: XYZ: command not found
Please let me know what went wrong.
Thanks in advance.
Try removing the whitespace before EOF
function ABC
{
sqlplus -s $ur1/$pwd#$SID << EOF
delete from table1 where row_name = 'A1';
delete from table2 where row_name = 'A2';
exit
EOF
}
I tried this in a sample program and it fixed the problem.
The format of here-documents is:
<<WORD
here-document content ...
here-document content ...
here-document content ...
WORD
WORD can be any label you like, but the end marker must be the only thing on the line, no whitespaces before or after.
In your example functions you are using eof and EOF as labels, you should remove the space characters from in front of them so that they are really at the beginning of the line, like this:
function ABC
{
sqlplus -s $ur1/$pwd#$SID << EOF
delete from table1 where row_name = 'A1';
delete from table2 where row_name = 'A2';
exit
EOF
}
function XYZ
{
sqlplus eip_dba/eip_dba$result#${input} << eof
set timing off
# ... and so on ....
eof
}
That is, the ending EOF and eof are right at the beginning of the line, with no trailing spaces either.

Resources