bash sqlcmd variable array - bash

I´m trying to acces values in a variable I receive from an sqlcmd in a loop:
while read line ;do AllNumbers=`sqlcmd -h -1 -S mysqlserver.localdomain -U Me -P MyPasswd -d master -Q "SET nocount on; SELECT PHONENUMBER FROM MYTABLE WHERE USER LIKE '"$line"' " < /dev/null`; for i in "$AllNumbers"; do echo "$line $i"; done; done< mytext.txt
The Number of results in the variable "$AllNumbers" can be 1 to 5, and the lenght of the number can also vary.
What I get in Moment is:
John 01234567
9876543
Jack 13579024
Jim 08642135
10293847
56473829
In the end I want to have an output like:
John 01234567
John 98765432
Jack 13579024
Jim 08642135
Jim 10293847
Jim 56473829
I tried with IFS, but I´m unsure what the delimiter in the variable $AllNumber is.
If I do:
OneUser=`sqlcmd -h -1 -S mysqlserver.localdomain -U Me -P MyPasswd -d master -Q "SET nocount on; SELECT PHONENUMBER FROM MYTABLE WHERE USER LIKE '"Jim"' "`; echo "$OneUSer"
I get:
08642135
10293847
56473829
I´m glad for any hint...
Thanks in advance
Lotte

Why not ask the database to do the hard work?
SELECT USER, PHONENUMBER FROM MYTABLE WHERE USER LIKE '"$line"'
Also, make sure you validate $line to prevent SQL injection attacks (see Bobby Tables).

Related

Bash Select Formatting

I have setup a script I can run to connect to my servers, which are contained in a json string variable.
While the script works just fine, I am finding that I do not really care too much for the select output as it shows me the entire row. What I would like to do is simply display the server yet still return the ip and user.
Is this possible? If so, how? Here is my code:
#!/bin/bash
_key="/home/MyUser/Documents/Keys/MyKey.pem"
# our server json
_servers='[{"server":"server1","ip":"10.0.0.1","user":"root"},{"server":"server2","ip":"10.0.0.2","user":"ubuntu"},{"server":"server3","ip":"192.168.4.112","user":"ec2-user"}]';
# loop over the items and display the server
echo "- Select a server to connect to: "
select _t in $(echo ${_servers} | jq -c '.[]'); do
# will keep asking until valid value given
[ -n "$_t" ] && break
done
# parse the selected row
_server=$(echo $_t | jq '.server');
_ip=$(echo $_t | jq '.ip');
_user=$(echo $_t | jq '.user');
echo "Connnecting to: ${_server:1:-1}";
sleep 2
#echo ${_ip:1:-1}
#echo ${_user:1:-1}
# make the connection
ssh -i $_key ${_user:1:-1}#${_ip:1:-1}
the select currently shows me:
me#MyMachine:~/Desktop# bash test
- Select a server to connect to:
1) {"server":"server1","ip":"10.0.0.1","user":"root"}
2) {"server":"server2","ip":"10.0.0.2","user":"ubuntu"}
3) {"server":"server3","ip":"192.168.4.112","user":"ec2-user"}
#?
And what I would like it to show instead:
me#MyMachine:~/Desktop# bash test
- Select a server to connect to:
1) server1
2) server2
3) server3
#?
You need an associative array that maps a server name to the JSON object representing that server.
declare -A servers
while read -r name data; do
servers[$name]=$data
done < <(jq -rc '.[] | "\(.server) \(.)"' <<< "$_servers")
Then you'll select a server name, and process the associate data after the select statement.
select _t in "${!servers[#]}"; do
[ -n "$_t" ] && break
done
read _server _ip _user < <(jq -rc '[.server, .ip, .user][]' <<< "${servers[$_t]}"
Alternatively, process the JSON once and store the IP addresses and user names in separate arrays.
declare -A ips users
while read -r _server _ip _user; do
ips[$_server]=$_ip
users[$_server]=$_user
done < <(jq -rc '.[] | "\(.server) \(.ip) \(.user)"' <<< "$_servers")
select _server in "${!ips[#]}"; do # could use "${!users[#]}" as well
[ -n "$_server" ] && break
done
_ip=${ips[$_server]}
_user=${users[$_user]}

Linux, Bash Script - Loop through sqlcmd connection SELECT results

Linux, Bash Script.
I have created a query as below, which works
sqlcmd -S [dbname].database.windows.net -d [database name]-U [username ]-P [password] -Q "SELECT * FROM dbo.microiopenvpn WHERE mode='create'"
How do I then loop over results.
The table has name, email_address & mode fields.
I just want the email_address field (for this query)
Figured it out - one way I guess
while IFS="," read -r d1 d2 d3 d4 d5 d6; do
echo "$d1" "$d2" "$d4"
done < sqloutputNew.csv
Get the column from each row, then iterates, seems to be the best solution I could find.
With the SQL having an output as below
-o "sqloutputNew.csv" -W -w 1024 -s"," -h-1

Assert on the postgres count output using bash

I would like to make an assertion the output of a postgres query using bash. Concretely, I am writing a bash job that counts the number of rows and if the count is not equal to zero, does something to raise alert.
$ psql MY_DATABASE -c "SELECT COUNT(*) WHERE foo=bar"
count
-------
0
(1 row)
In my script, I would like to assert that the output of above query is zero. However I am not sure where to begin because the output is not a number, but a formatted multi line string.
Is there an option in psql that makes it output a single number when counting, or could you think of any other approaches?
I would suggest to use temporary file to redirect the output and use it. Once your work is done, delete the temp file.
psql your_database -c "SELECT COUNT(*) as Count from table_a where c1=something" -t >assert.tmp
line=$(head -n 1 assert.tmp)
if [ $line -ge 0 ]; then
echo "greater then 0 and values is--"$line
fi
rm assert.tmp
Hope it works for you.

Tabulate part of text file written by shell

I have a shell script that is writing(echoing) the output on an array to a file. The file is in the following format
The tansaction detials for today are 35
Please check the 5 biggest transactions below
-----------------------------------------------------------------------------------
Client Name,Account Number,Amount,Tran Time
Michael Press,20484,602117,11.41.02
Adam West,164121,50152,11.41.06
John Smith,15113,411700,11.41.07
Leo Anderson,2115116,350056,11.41.07
Wayne Clark,451987,296503,11.41.08
And i have multiple such line.
How do i tabulate the names after ---?
I tried using spaces while echoing the array elements. Also tried tabs. I tried using column -t -s options. But the text above the --- is interfering with the desired output.
The desired output is
The tansaction detials for today are 35
Please check the 5 biggest transactions below
-----------------------------------------------------------------------------------
Client Name Account Number Amount Tran Time
Michael Press 20484 602117 11.41.02
Adam West 164121 50152 11.41.06
John Smith 15113 411700 11.41.07
Leo Anderson 2115116 350056 11.41.07
Wayne Clark 451987 296503 11.41.08
The printing to a file is a part of a bigger script. So, i am looking for a simple solution to plug into this script.
Here's the snippet from that script where i am echoing to the file.
echo "The tansaction detials for today are 35 " >> log.txt
echo "" >> log.txt
echo " Please check the 5 biggest transactios below " >> log.txt
echo "" >> log.txt
echo "-----------------------------------------------------------------------------------" >> log.txt
echo "" >> log.txt
echo "" >> log.txt
echo "Client Name,Account Number,Amount,Tran Time" >> log.txt
array=( `output from a different script` )
x=1
for i in ${array[#]}
do
#echo "Array $x - $i"
Clientname=$(echo $i | cut -f1 -d',')
accountno=$(echo $i | cut -f2 -d',')
amount=$(echo $i | cut -f3 -d',')
trantime=$(echo $i | cut -f4 -d',')
echo "$Clientname,$accountno,$amount,$trantime" >> log.txt
(( x=$x+1 ))
done
I'm not sure to understand everythings =P
but to answer this question :
How do i tabulate the names after ---?
echo -e "Example1\tExample2"
-e means : enable interpretation of backslash escapes
So for your output, I suggest :
echo -e "$Clientname\t$accountno\t$amount\t$trantime" >> log.txt
Edit : If you need more space, you can double,triple,... it
echo -e "Example1\t\tExample2"
If I understand your question, in order to produce the output format of:
Client Name Account Number Amount Tran Time
Michael Press 20484 602117 11.41.02
Adam West 164121 50152 11.41.06
John Smith 15113 411700 11.41.07
Leo Anderson 2115116 350056 11.41.07
Wayne Clark 451987 296503 11.41.08
You should use the output formatting provided by printf instead of echo. For example, for the headings, you can use:
printf "Client Name Account Number Amount Tran Time\n" >> log.txt
instead of:
echo "Client Name,Account Number,Amount,Tran Time" >> log.txt
For writing the five largest amounts and details, you could use:
printf "%-14s%-17s%8s%s\n" "$Clientname" "$accountno" "$amount" "$trantime" >> log.txt
instead of:
echo "$Clientname,$accountno,$amount,$trantime" >> log.txt
If that isn't what you are needing, just drop a comment and let me know and I'm happy to help further.
(you may have to tweak the field widths a bit, I just did a rough count)
True Tabular Output Requires Measuring Each Field
If you want to insure that your data is always in tabular form, you need to measure each field width (including the heading) and then take the max of either the field width (or heading) to set the field width for your output. Below is an example of how that can be done (using your simulated other program input):
#!/bin/bash
ofn="log.txt" # set output filename
# declare variables as array and integer types
declare -a line_arr hdg name acct amt trn tmp
declare -i nmx=0 acmx=0 ammx=0 tmx=0
# set heading array (so you can measure lengths)
hdg=( "Client Name"
"Account Number"
"Ammount"
"Tran Time" )
## set the initial max based on headings
nmx="${#hdg[0]}" # max name width
acmx="${#hdg[1]}" # max account width
ammx="${#hdg[2]}" # max ammount width
tmx="${#hdg[3]}" # max tran width
{ IFS=$'\n' # your array=( `output from a different script` )
line_arr=($(
cat << EOF
Michael Press,20484,602117,11.41.02
Adam West,164121,50152,11.41.06
John Smith,15113,411700,11.41.07
Leo Anderson,2115116,350056,11.41.07
Wayne Clark,451987,296503,11.41.08
EOF
)
)
}
# write heading to file
cat << EOF > "$ofn"
The tansaction detials for today are 35
Please check the 5 biggest transactions below
-----------------------------------------------------------------------------------
EOF
# read line array into tmp, compare to max field widths
{ IFS=$','
for i in "${line_arr[#]}"; do
tmp=( $(printf "%s" "$i") )
((${#tmp[0]} > nmx )) && nmx=${#tmp[0]}
((${#tmp[1]} > acmx )) && acmx=${#tmp[1]}
((${#tmp[2]} > ammx )) && ammx=${#tmp[2]}
((${#tmp[3]} > tmx )) && tmx=${#tmp[3]}
name+=( "${tmp[0]}" ) # fill name array
acct+=( "${tmp[1]}" ) # fill account num array
amt+=( "${tmp[2]}" ) # fill amount array
trn+=( "${tmp[3]}" ) # fill tran array
done
}
printf "%-*s %-*s %-*s %s\n" "$nmx" "${hdg[0]}" "$acmx" "${hdg[1]}" \
"$ammx" "${hdg[2]}" "${hdg[3]}" >> "$ofn"
for ((i = 0; i < ${#name[#]}; i++)); do
printf "%-*s %-*s %-*s %s\n" "$nmx" "${name[i]}" "$acmx" "${acct[i]}" \
"$ammx" "${amt[i]}" "${trn[i]}" >> "$ofn"
done
(you can remove the extra space between each field in the final two printf statements if you only want a single space between them -- looked better with 2 to me)
Output to log.txt
$ cat log.txt
The tansaction detials for today are 35
Please check the 5 biggest transactions below
-----------------------------------------------------------------------------------
Client Name Account Number Ammount Tran Time
Michael Press 20484 602117 11.41.02
Adam West 164121 50152 11.41.06
John Smith 15113 411700 11.41.07
Leo Anderson 2115116 350056 11.41.07
Wayne Clark 451987 296503 11.41.08
Look things over and let me know if you have any questions.

Passing IFS values to a dynamic array

i have a Oracle output (select output) as cand1 cand2 cand3 cand62
now i need to store these values in an array through shell script.
#!/bin/bash
instant_client="/root/ora_client/instantclient_11_2"
output=`$instant_client/sqlplus -s HRUSER/HRUSER#TOMLWF <<EOF
set heading off
set feedback off
set lines 10000
set pagesize 10000
select count (1) from onboardingcandidates o, candidatedetails c where o.candidateid=c.candidateid and o.JOININGSTATUS='0091' and to_date(o.joiningdate)=to_date(sysdate+5);
EOF
exit
query=`$instant_client/sqlplus -s HRUSER/HRUSER#TOMLWF <<EOF
set heading off
set feedback off
set lines 10000
set pagesize 10000
select o.candidateid from onboardingcandidates o, candidatedetails c where o.candidateid=c.candidateid and o.JOININGSTATUS='0091' and to_date(o.joiningdate)=to_date(sysdate+5);
EOF
exit
i=0
echo "Throwing individual arrays:"
while [ $i -le $output ]
do
a=${query[$i]}
echo Candidate[$i]=$a
i=$(($i+1))
done
OUTPUT IS
Throwing individual arrays:
Candidate[0]= cand1 cand2 cand3 cand62
Candidate[1]=
Candidate[2]=
Candidate[3]=
Candidate[4]=
REQUIRED OUTPUT
Throwing individual arrays:
Candidate[0]= cand1
Candidate[1]= cand2
Candidate[2]= cand3
Candidate[3]= cand62
The problem is that query is a string, not an array, so ${query[$i]} does not work as you expect.
In general, to convert a string to an array you would do this:
$ string="foo bar"
$ array=($string)
$ echo ${array[0]}
foo
$ echo ${array[1]}
bar
In your case, if you surround the sqlplus command with parentheses, the output will be stored in an array. Like this:
query=(`$instant_client/sqlplus -s HRUSER/HRUSER#TOMLWF <<EOF
set heading off
set feedback off
set lines 10000
set pagesize 10000
select o.candidateid from onboardingcandidates o, candidatedetails c where o.candidateid=c.candidateid and o.JOININGSTATUS='0091' and to_date(o.joiningdate)=to_date(sysdate+5);
EOF)
And then you can access elements in the query array using an index: ${query[$i]}
Something like this:
$ query="cand1 cand2 cand3 cand62"
$ read -a Candidate <<<$query
$ echo ${Candidate[0]}
cand1
$ echo ${Candidate[1]}
cand2
When you are out of your sqlplus, your "query" variable contains something like above. By simply reading the entire thing into an array as shown above, you can access the values.

Resources