bash - how to iterate a list/array through a parameterized bash script - bash

I have a bash script where I pass the following arguments (its using getopts) like so:
./test.sh -o c03 -d mydb -t tblA -n c13 -r us-east-1
The execution works however, I need to alter this where -t (for table) needs to be a list of tables (tblA, tblB, tblC).
So, in a single run, I'm trying to generate the following:
./test.sh -o c03 -d mydb -t tblA -n c13 -r us-east-1
./test.sh -o c03 -d mydb -t tblB -n c13 -r us-east-1
./test.sh -o c03 -d mydb -t tblC -n c13 -r us-east-1
How can I do this?

Try this for loop:
for i in A B C; do
./test.sh -o c03 -d mydb -t tbl"$i" c13 -r us-east-1
done

How about leveraging bash and use variable range? This would make a difference if you have to deal with large range.
for i in {A..C}
do
./test.sh -o c03 -d mydb -t tbl"$i" c13 -r us-east-1
done

Related

while loop with global variable scope issue in shell script with psql

I am fetching the data from psql in the shell script and assign to the global variable but the global variable is not updating below i have tried:
#!/bin/bash
res_count=0
psql -h $db_host -U $db_user -d $db_name -At -c "select count(id) as dCount from abc" --no-password --field-separator ' ' | \
while read dCount ; do
res_count=$dCount
done;
echo $res_count
$res_count is not updating, it has still value 0, please correct me where i am wrong thanks
Your while loop executes in a subshell because it is executed as part of the pipeline. You can avoid it by using lastpipe or placing the psql command inside process substitution.
#/bin/bash
shopt -s lastpipe
...
Or
res_count=0
while read dCount ; do
res_count=$dCount
done < <(psql -h "$db_host" -U "$db_user" -d "$db_name" -At \
-c "select count(id) as dCount from abc"
--no-password --field-separator ' ')
echo "$res_count"
As a side note, quote your variables properly.

Environment variables not defined in SSH AuthorizedKeysCommand (Docker)

I'm trying to make the private key SSH connection with LDAP.
/etc/ssh/sshd_config
AuthorizedKeysCommand /etc/ldap_ssh_authorized_keys.sh
AuthorizedKeysCommandUser nobody
Script to get public keys from LDAP server
/etc/ldap_ssh_authorized_keys.sh
#!/bin/bash
USERSLIST=$( ldapsearch -x -D "${LDAP_USER}" -w "${LDAP_PASSWORD}" -H $LDAP_URI -b "${LDAP_BASEDN}" -s sub '(objectClass=posixAccount)' -u 'uid' \
grep '^uid:' | sed -n '/^ /{H;d};/uid:/x;$g;s/\n *//g;s/uid: //gp' \
)
while IFS= read -r line; do
exists=$(ldapsearch -x -D "${LDAP_USER}" -w "${LDAP_PASSWORD}" -H $LDAP_URI -b "${LDAP_BASEDN}" \
-s sub "(&(objectClass=posixGroup)(cn=sysadmin)(memberUid=${line}))" | grep "^# numEntries:")
if [[ ! -z $exists ]]
then
ldapsearch -x -D "${LDAP_USER}" -w "${LDAP_PASSWORD}" -H $LDAP_URI -b "${LDAP_BASEDN}" \
-s sub "(&(objectClass=posixAccount)(uid=${line}))" \
-u 'sshPublicKey' \
| sed -n '/^ /{H;d};/sshPublicKey:/x;$g;s/\n *//g;s/sshPublicKey: //gp'
echo -e "";
fi;
done <<< "$USERSLIST"
When I'm running script with /bin/bash it's working well and return my public keys.
All environment variables defined normally.
LDAP_URI
LDAP_BASEDN
LDAP_USER
LDAP_PASSWORD
The script also running normally when trying to make an SSH connection. But environment variables not available.
I'm trying also with AuthorizedKeysCommandUser as root. But nothing changed.
I solved this problem by getting the environment variables from /proc/1/environ.
Reference

unable to remove footer for psql ressult in shell script

I have a psql command where I am able to get result but i unable to remove footer
my command
sshpass -p 'password' ssh mptios#xx.xx.xxx.xxx "PGPASSWORD=xxxxx psql -a -h 11.11.111.11 -d TGM_bb_les -U bi_it -t -c \"select count(1) from dwpub.td_bank \" "
my result for above command :-
select count(1) from dwpub.td_bank
29
but I need output as
29
I have tried this command but still unable to get expected output
sshpass -p 'password' ssh mptios#xx.xx.xxx.xxx "PGPASSWORD=xxxxx psql -a -h 11.11.111.11 -d TGM_bb_les -U bi_it --pset\"footer=off\" -c \"select count(1) from dwpub.td_bank \" "
can anyone help me with this
Use grep or egrep to match digits only.
sshpass -p 'password' ssh mptios#xx.xx.xxx.xxx "PGPASSWORD=xxxxx psql -a -h 11.11.111.11 -d TGM_bb_les -U bi_it --pset\"footer=off\" -c \"select count(1) from dwpub.td_bank \" " | grep -Eo '[0-9]+$'
Try with command:
sshpass -p 'password' ssh mptios#xx.xx.xxx.xxx "PGPASSWORD=xxxxx psql -a -h 11.11.111.11 -d TGM_bb_les -U bi_it -t -c \"select count(1) from dwpub.td_bank \" "|tail -1
This will show only the last line

How to run 2 loops simultaneously in bash script

I am very new in writing code, so it might be a silly question, but an answer is highly appreciated to enhance my learning. I have written a simple bash script as below. But how can I optimize this code by using loop, array? I can understand if I use two loops, I can make the lines of code shorter. Please help:
#!/bin/bash
zs=10.0.3.10
zb=/usr/local/bin/zabbix_sender
zh=zabbix
# ql1 = queue link
ql1=https://sqs.us-west-2.amazonaws.com/843390035802/testService1
val1=$(aws sqs get-queue-attributes --queue-url $ql1 --attribute-names ApproximateNumberOfMessages --region us-west-2 --output text | awk '{print $2}')
echo "$ql1 count is $val1"
$zb -z $zs -s $zh -k testService1 -o val1 >/dev/null 2>&1
ql2=https://sqs.us-west-2.amazonaws.com/853390078801/testService2
val2=$(aws sqs get-queue-attributes --queue-url $ql2 --attribute-names ApproximateNumberOfMessages --region us-west-2 --output text | awk '{print $2}')
echo "$ql2 count is $val2"
$zb -z $zs -s $zh -k testService2 -o val2 >/dev/null 2>&1
ql3=https://sqs.us-west-2.amazonaws.com/843393305801/testService3
val3=$(aws sqs get-queue-attributes --queue-url $ql3 --attribute-names ApproximateNumberOfMessages --region us-west-2 --output text | awk '{print $2}')
echo "$ql3 count is $val3"
$zb -z $zs -s $zh -k testService3 -o val3 >/dev/null 2>&1
ql4=https://sqs.us-west-2.amazonaws.com/875660005801/testService4
val4=$(aws sqs get-queue-attributes --queue-url $ql4 --attribute-names ApproximateNumberOfMessages --region us-west-2 --output text | awk '{print $2}')
echo "$ql4 count is $val4"
$zb -z $zs -s $zh -k testService4 -o val4 >/dev/null 2>&1
ql5=https://sqs.us-west-2.amazonaws.com/843390635802/testService5
val5=$(aws sqs get-queue-attributes --queue-url $ql5 --attribute-names ApproximateNumberOfMessages --region us-west-2 --output text | awk '{print $2}')
echo "$ql5 count is $val5"
$zb -z $zs -s $zh -k testService2 -o val5 >/dev/null 2>&1
In above code at this step
$zb -z $zs -s $zh -k testService2 -o val5 >/dev/null 2>&1 I used -k as different 5 values. So how can I arrange it and work the code as same as above?
One loop is sufficient to eliminate the code duplication, and we don't need an array - we can read one queue link after the other in the loop. The variable argument to the option -k can be extracted from the queue link by removing the URL part up to to last / with the shell parameter expansion ${parameter##word}.
zs=10.0.3.10
zb=/usr/local/bin/zabbix_sender
zh=zabbix
# ql = queue link
while read ql
do
val=$(aws sqs get-queue-attributes --queue-url $ql --attribute-names ApproximateNumberOfMessages --region us-west-2 --output text | awk '{print $2}')
echo "$ql count is $val"
$zb -z $zs -s $zh -k ${ql##*/} -o $val >/dev/null 2>&1
done <<END
https://sqs.us-west-2.amazonaws.com/843390035802/testService1
https://sqs.us-west-2.amazonaws.com/853390078801/testService2
https://sqs.us-west-2.amazonaws.com/843393305801/testService3
https://sqs.us-west-2.amazonaws.com/875660005801/testService4
https://sqs.us-west-2.amazonaws.com/843390635802/testService5
END

psql --(record|field)-separator NUL

Is there some way to make psql separate the fields and records by \0, aka NUL? It's the only way to be able to pass arbitrary data to Bash scripts.
Based on Matthew Wood's answer, I would expect this to print more that 1 on a newly initialized database:
declare -i count=0
echo "\pset recordsep '\000'
\f '\000'
select typname from pg_type" | \
sudo -iu postgres psql --no-align --quiet --tuples-only -d dbname -U username | while IFS= read -r -d ''
do
#echo "$REPLY"
let count++
done
if [ -n "$REPLY" ]
then
#echo "$REPLY"
let count++
fi
echo $count
Workaround: Iff the SELECT results are unique, you can use this workaround to handle one at a time:
next_record() {
psql --no-align --quiet --tuples-only -d dbname -U username <<SQL
SELECT colname
FROM tablename
WHERE colname > '${1}'
ORDER BY colname
LIMIT 1
SQL
}
last_col=
while true
do
colx="$(next_record "$last_col"; printf x)"
if [ "$colx" = x ]
then
exit
fi
col="${colx%$'\nx'}" # The extra \n character is from psql
# Do your thing here
col_escaped="${col//"'"/''}" # Double single quotes
col_escaped="${col_escaped//\\/\\\\}" # Double backslashes
last_col="$col_escaped"
done
This is not supported. psql uses C print functions to print out the result tables, and printing a zero byte just doesn't work there.
Update: This is now supported in PostgreSQL 9.2-to-be (git).
Try this:
psql --field-separator '\000' --no-align -c '<your query>'
Edit: Maybe not. However, it appear to work in psql using these commands:
\f '\000'
\a
Newer versions of psql support the --field-separator-zero flag.

Resources