I have a below shell script which reads a file and updates the table. But the problem with the below code is that a connection is established for running each sql statements. I am looking for recommendation to enhance this code.
#!/bin/bash
input="/Users/temp/newfile.txt"
while IFS= read -r var
do
echo "update keyspace.tableName set randomColumn='randomText' where random_id='$var'; exit" | ./cqlsh serverName -u username -p password
if [ $? -eq 0 ]; then
echo SUCCESS
echo "select random_id,randomColumn from keyspace.tableName where random_id='$var'; exit" | ./cqlsh serverName -u username -p password
else
echo FAIL
fi
done < "$input"
I suggest doing this with the Python driver if you'd like better performance.
This example should be roughly equivalent:
#! /usr/bin/env python3
from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider
cluster = Cluster(auth_provider=PlainTextAuthProvider(username='cassandra', password='cassandra'))
session = cluster.connect()
with open("/Users/temp/newfile.txt") as f:
for line in f:
try:
rows = session.execute("UPDATE keyspace.tableName SET randomColumn='randomText' WHERE random_id=%(var)s", {'var'=line})
print("SUCCESS")
for r in rows:
print(r)
except Exception:
print("FAIL")
edit: you can even go a step further and use prepared statements and async queries, which will provide very significant performance increases if you are making a large volume of queries.
cqlsh has a -f option which allows to run cql statement from a file. You could generate the cql statements by parsing your newfile.txt and then run cqlsh with -f option
At the very basic level, you could do something like this:
#!/bin/bash
input="newfile.txt"
while IFS= read -r var
do
echo "update ks.t1 set name='randomText' where id=$var;" >> result
done < "$input"
./cqlsh serverName -u username -p password -f result
if [ $? -eq 0 ]; then
echo SUCCESS
echo "select * from keyspace.tableName; exit" | ./cqlsh serverName -u username -p password
else
echo FAIL
fi
I suggest to use cqlsh -e with xargs :
#!/bin/bash
input="/Users/temp/newfile.txt"
while IFS= read -r var
do
echo "update keyspace.tableName set randomColumn='randomText' where random_id='$var';" | xargs cqlsh serverName -u 'username' -p 'password' -e
if [ $? -eq 0 ]; then
echo SUCCESS
echo "select random_id,randomColumn from keyspace.tableName where random_id='$var';" | xargs cqlsh serverName -u 'username' -p 'password' -e
else
echo FAIL
fi
done < "$input"
Related
Code works fine until the last for loop.
It tries to login database. Either, it establish a successful connection with database or not, script gives output OK/NOT OK depending to the connection and then exit the shell script. What should I do to solve this?
#!/bin/bash
read -p 'Username: ' var_username
read -sp 'Password: ' var_password
filename="$1"
while read -r line; do
name=$(sed 's/#.*$//g; s/(.*$//g; s/=.*$//g; s/).*$//g')
done < "$filename"
#retval=$? | tail -n1|grep OK
for tns in $name
do
tnsping $tns
if [ $? -eq 1 ]; then
echo $tns 'tnsping i calismiyor' >>tnslatest.log
else
echo $tns 'tnsping i calisiyor' >>tnslatest.log
working_tns+=($tns)
fi
done
#The following lines do not work properly.#
for working in $working_tns
do
echo "exit" | sqlplus -L $var_username/$var_password#$working | grep
Connected > /dev/null
if [ $? -eq 0 ]
then
echo "OK"
else
echo "NOT OK"
fi
done
For example; my tnsnames.ora file contains 4 tns.
So, I want to have for output like OK or NOT OK in total.
Thanks in advance.
my script refuses to work under cron, but works fine while executing manually
#!/bin/bash
LOGFILE=/opt/xxx/scripts/rc.log
fUpMail() {
echo -e "Hello!\n\n$1 xx\n\nBest regards,\n\nCheck LLC 2k18" | mailx -s "$1 Rates were not imported" smone#smth.com
}
curDate=`date +%Y-%m-%d`
#postgres expression output being assigned to a variable
rateQ=`PGPASSWORD=xxxxxx psql -t -h xxx.xxx.228.134 -p 5433 -d axx2 -U axxx2bo << EOF
SELECT COUNT(id) FROM quote WHERE f_date = '$curDate'
EOF`
#same for demodb
rateDemo=`PGPASSWORD=xxx psql -t -h xx.xxx.42.14 -p 5432 -d axxxo -U acxxxxbo << EOF
SELECT COUNT(id) FROM quote WHERE f_date = '$curDate'
EOF`
#logging
printf "\n`date +%H:%M:%S` $curDate $rateQ $rateDemo\n" >> $LOGFILE
#check if rate value is not null
if [[ $(($rateQ)) != 0 ]] && [[ $(($rateDemo)) != 0 ]];
then
#posting a commentary into jira
curl -u xxx-support-bot:Rzq-xxx-xxx-gch -X POST --data '{"body": "'"$rateQ"' LIVE rates for '"$curDate"' were imported automatically'"\n"''"$rateDemo"' DEMO rates for '"$curDate"' were imported automatically"}' -H "Content-type: application/json" https://jira.in.xxx.com:443/rest/api/2/issue/xxxxxx-1024/comment >> $LOGFILE
else
#if rates were not imported
if [[ $(($rateQ)) == 0 ]];
then
echo "looks like LIVE rates for $curDate were not imported, please check manually!"
#sending a letter
fUpMail 'LIVE'
fi
if [[ $(($rateDemo)) == 0 ]];
then
echo "looks like DEMO rates for $curDate were not imported, please check manually!"
fUpMail 'DEMO'
fi
fi
cron sends following message:
/opt/xxx/scripts/ratecheck.sh: line 25: Timing is on.
6543
Time: 4.555 ms: syntax error: invalid arithmetic operator (error token is ".
6543
Time: 4.555 ms")
line 25 is
if [[ $(($rateQ)) != 0 ]] && [[ $(($rateDemo)) != 0 ]];
Could please someone help explaining what's wrong here?
You're getting more than a plain number back from psql and this is interfering with the type conversion you're doing. I think you can remove the extra output like this:
rateQ=$(PGPASSWORD=xxxxxx psql -t -h xxx.xxx.228.134 -p 5433 -d axx2 -U axxx2bo -q -c "SELECT COUNT(id) FROM quote WHERE f_date = '$curDate'")
rateDemo=$(PGPASSWORD=xxx psql -t -h xx.xxx.42.14 -p 5432 -d axxxo -U acxxxxbo -q -c "SELECT COUNT(id) FROM quote WHERE f_date = '$curDate'")
Note the addition of the -q flag:
-q
--quiet
Specifies that psql should do its work quietly. By default, it prints welcome messages and various informational output. If this option is used, none of this happens. This is useful with the -c option. This is equivalent to setting the variable QUIET to on.
https://www.postgresql.org/docs/9.0/app-psql.html
I also replaced your old-fashioned backticks with $() and put the SQL query into an argument.
If that doesn’t silence the additional output, you may also need to edit ~/.psqlrc for the user running the cron job and ensure there is no \timing line.
Running in a docker container, I am trying to determine if a table exits in the mssql database:
RESULT='/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -d master -i "SELECT name FROM master.sys.databases WHERE name = N'MyTable'"'
if [ "$RESULT" == "MyTable" ]; then
echo YES
fi
echo "$RESULT"
echo "$RESULT" always just outputs the entire command as a string, its not getting executed. So its just assigning it as a sting...
How can I execute it and assign the result?
Bash does not execute commands defined in single quotes. Single quotes are used for string definitions.
What you try to do is called command substitution. And it can be done in two different ways:
RESULT=`command`
RESULT=$(command)
So your example should look like this:
RESULT=`/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -d master -i "SELECT name FROM master.sys.databases WHERE name = 'MyTable'`
if [ "$RESULT" == "MyTable" ]; then
echo YES
fi
echo "$RESULT"
You can find more information regarding command substitution here:
https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html
I have the following bash script deploy.sh:
#!/usr/bin/env bash
# Some useful resources:
# while read ip user pass; do : http://unix.stackexchange.com/questions/92664/how-to-deploy-programs-on-multiple-machines
# -o StrictHostKeyChecking=no: http://askubuntu.com/questions/180860/regarding-host-key-verification-failed
# -T: http://stackoverflow.com/questions/21659637/how-to-fix-sudo-no-tty-present-and-no-askpass-program-specified-error
# echo $pass |: http://stackoverflow.com/questions/11955298/use-sudo-with-password-as-parameter
while read ip user pass; do
echo $ip
sshpass -p "$pass" ssh $user#$ip -o StrictHostKeyChecking=no -T "
echo 'yo'
"
echo 'done'
done < servers.txt
servers.txt contains:
53.12.45.74 my_username my_password
54.12.45.74 my_username my_password
57.12.45.74 my_username my_password
From my understanding, the while read ip user pass; do […] done < servers.txt should loop over all three lines of servers.txt.
However, when I try to run it, it only performs one iteration:
ubuntu#server:~$ bash deploy.sh
53.12.45.74
yo
done
ubuntu#server:~$
Why?
If the loop is simply:
while read ip user pass; do
echo $ip
done < servers.txt
it does perform all three iterations:
ubuntu#server:~$ bash deploy.sh
53.12.45.74
54.12.45.74
57.12.45.74
ubuntu#server:~$
sshpass is taking control of stdin or possibly replacing it and causing while loop to lose input from redirected stdin.
To work around this issue, avoid reading from stdin.
First, load the file into an array using a while loop.
while read line; do
entries+=("$line")
done < servers.txt
Next, use for loop to parse the lines and execute sshpass within this loop.
for line in "${entries[#]}"; do
set $line
ip=$1
user=$2
pass=$3
echo $ip
sshpass -p "$pass" ssh $user#$ip -o StrictHostKeyChecking=no -T "
echo 'yo'
"
echo 'done'
done
The second loop doesn't read from stdin.
But I will recommend Rany Albeg Wein answer using a separate descriptor than the current stdin.
while read ip user pass <&3; do
echo $ip
sshpass -p "$pass" ssh $user#$ip -o StrictHostKeyChecking=no -T "
echo 'yo'
"
echo 'done'
done 3<servers.txt
#!/usr/bin/env bash
# Some useful resources:
# while read ip user pass; do : http://unix.stackexchange.com/questions/92664/how-to-deploy-programs-on-multiple-machines
# -o StrictHostKeyChecking=no: http://askubuntu.com/questions/180860/regarding-host-key-verification-failed
# -T: http://stackoverflow.com/questions/21659637/how-to-fix-sudo-no-tty-present-and-no-askpass-program-specified-error
# echo $pass |: http://stackoverflow.com/questions/11955298/use-sudo-with-password-as-parameter
while read ip user pass; do
if [ -n "$ip" ]; then
echo "IP[$ip] USER[$user] PASS[$pass]";
# dont forget to uncomment this two lines here:
#sshpass -p "$pass" ssh $user#$ip -o StrictHostKeyChecking=no -T "
#echo 'yo'
echo ""; # Just a blank line"
echo "done.";
else
echo "Empty value.";
fi
done < servers.txt
So, now it works.
I am coding a script to select some IPs from a table in a DB, and then use IPTables rules to ban theses IPs, last step is to notify by e-mail, but I am getting 2 errors:
#!/bin/bash
Now=$(date +"%d-%m-%Y %T")
fileLocation="/var/lib/mysql/DBName/"
fileName="ip2ban.txt"
filePath=$fileLocation$fileName
curLocation=$(pwd)
#Connect to DB and select ban_ip
mysql -u root -pPASSWORD -D DBName -e 'SELECT ip INTO OUTFILE "'$filePath'" FROM ban_ip WHERE ip_tables = "0"' >> banIP.log 2>&1
selRes=$?
# If the command was successful
if [ $selRes -eq "0" ]
then
# We need to check if the file exists on the saved location
#find $fileLocation -type f -iname "ip2ban.txt" -empty => To check if file empty or not
if [ -f $filePath ]
then
mv $filePath $curLocation'/ip2ban.txt'
# Connect to DB and update the ban_ip
mysql -u root -pPASSWORD -D DBName -e 'UPDATE ban_ip SET ip_tables = "1" WHERE ip_tables = "0"' >> banIP.log 2>&1
upRes=$?
if [ $upRes -eq "0" ]
then
# Send message for succesful result
echo -e "Database updated with new banned IPs on $Now \nThank you for using this script" 2>&1 | sed '1!b;s/^/To: myID#gmail.com\nSubject: New banned IPs[Success]\n\n/' | sendmail -t
else
# Send message for failure result
echo -e "We cannot update the ban_ip table on $Now \nThank you for using this script" 2>&1 | sed '1!b;s/^/To: myID#gmail.com\nSubject: [Failure] New banned IPs\n\n/' | sendmail -t
fi
fi
else
echo 'Something wrong with Select statment on' $Now >> banIP.log
fi
# Save IPTables rules
iptables-save > /root/Scripts/IPTables/BannedIPs.conf // LIGNE 53
I am getting 2 errors:
line 53: iptables-save: command not found
line 37: sendmail: command not found
However the sendamil is already installed, with mail, postfix:
# which sendmail
/usr/sbin/sendmail
# which mail
/usr/bin/mail
# which postfix
/usr/sbin/postfix
Thanks for your usual support
According to the crontab(5) man page for Linux:
PATH is set to "/usr/bin:/bin".
Meaning your shell script will not be able to find anything under /usr/sbin or /sbin. Change this with by adding the following near the top of your script:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
Also the environment can be set from within the crontab. See https://stackoverflow.com/a/14694543/5766144 for how to do this.