sqlcmd in bash file - store to variable - bash

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

Related

Running cql statements with shell script

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"

How to execute a file that is located in $PATH

I am trying to execute a hallo_word.sh that is stored at ~/bin from this script that is stored at my ~/Desktop. I have made both scripts executable. But all the time I get the problem message. Any ideas?
#!/bin/sh
clear
dir="$PATH"
read -p "which file you want to execute" fl
echo ""
for fl in $dir
do
if [ -x "$fl" ]
then
echo "executing=====>"
./$fl
else
echo "Problem"
fi
done
This line has two problems:
for fl in $dir
$PATH is colon separated, but for expects whitespace separated values. You can change that by setting the IFS variable. This changes the FIELD SEPARATOR used by tools like for and awk.
$fl contains the name of the file you want to execute, but you overwrite its value with the contents of $dir.
Fixed:
#!/bin/sh
clear
read -p "which file you want to execute" file
echo
IFS=:
for dir in $PATH ; do
if [ -x "$dir/$file" ]
then
echo "executing $dir/$file"
exec "$dir/$file"
fi
done
echo "Problem"
You could also be lazy and let a subshell handle it.
PATH=(whatever) bash command -v my_command
if [ $? -ne 0 ]; then
# Problem, could not be found.
else
# No problem
fi
There is no need to over-complicate things.
command(1) is a builtin command that allows you to check if a command exists.
The PATH value contains all the directories in which executable files can be run without explicit qualification. So you can just call the command directly.
#!/bin/sh
clear
# r for raw input, e to use readline, add a space for clarity
read -rep "Which file you want to execute? " fl || exit 1
echo ""
"$fl" || { echo "Problem" ; exit 1 ; }
I quote the name as it could have spaces.
To test if the command exists before execution use type -p
#!/bin/sh
clear
# r for raw input, e to use readline, add a space for clarity
read -rep "Which file you want to execute? " fl || exit 1
echo ""
type -p "$fq" >/dev/null || exit 1
"$fl" || { echo "Problem" ; exit 1 ; }

Bash script take in parameter or present a select

We have a script we use to promote databases from dev to QA. Currently the script has a select statement we use to print out all the available databases and then takes your selection and does the various bits to promote the db.
I want to add a parameter to bypass that select statement for scripting purposes.
Here's how the script works currently:
# GET LIST OF DATABASES
DATABASES=`echo "show databases;"|/usr/bin/mysql -u root -h $DEVHOST|grep -v "information_schema"|grep -v "Database"|grep -v "performance_schema"|grep -v "mysql"`
eval set $DATABASES
select DEVDB in "$#"
do
if [[ "$DEVDB" =~ "dev1" ]]; then
QADB=`echo $DEVDB|sed -e s/_dev1_/_qa1_/`
fi
# Does various bits after this
Here's what I'm trying to do:
arg1=$1
if [ ! -z "$arg1" ]; then
DEVDB=$arg1
else
# GET LIST OF DATABASES
DATABASES=`echo "show databases;"|/usr/bin/mysql -u root -h $DEVHOST|grep -v "information_schema"|grep -v "Database"|grep -v "performance_schema"|grep -v "mysql"`
eval set $DATABASES
select DEVDB in "$#"
do
fi
if [[ "$DEVDB" =~ "dev1" ]]; then
QADB=`echo $DEVDB|sed -e s/_dev1_/_qa1_/`
fi
I'm getting an error at fi, I assume it's related to the select... do. How do I wrap these up in my if statements?
You need to do something in the body of the select. In this case it's sufficient to check that the variable has a value:
PS3="Select a database: "
select DEVDB; do
[[ $DEVDB ]] && break
done
echo "you selected $DEVDB"
Definitely don't need eval here -- it's always a code smell.
set -- $(
/usr/bin/mysql -u root -h $DEVHOST <<< "show databases;" |
grep -v -e information_schema -e Database -e performance_schema -e mysql
)

Bash script to search for LDAP entries

I have a bash script which is to be used to delete a particular user if it exists in a group.
First I extracted all the group names and saved it to a file. As the next step, I thought I should parse through the file, and use the ldapsearch command on all the entries and grep the user, and if it exists, use ldapmodify to delete it.
My question is how to write the if condition, i.e if [ *ldapsearch query* == True];then
This is what my ldapsearch looks like, and the first line inside the while loop is to be the if statement.
while read grp;do
ldapsearch -w 'ldappass' -D "cn=adminuser,dc=some-domain,dc=com" -b "cn=$grp,ou=group,dc=some-domain,dc=com" | grep $someuser
done</home/someuser/tempfile.txt
On the CLI, this ldapsearch query returns the following output;
memberUid: testuser
So essentially, if the if statement returns some value (i.e. the user exists), then I have to delete the user. How do I get a correct if statement to get a True or False result for the ldapsearch query?
You can use the -z option, that checks if the string is empty or not. [ -z "$string" ] is true if the string is empty. Then, this can make it:
if [ ! -z "$(yourcommand)" ]; then
do_things
fi
For example say we want to check if a directory is empty:
if [ ! -z "$(ls)" ]; then
echo "there is something"
else
echo "this dir is empty"
fi
All together:
while IFS= read -r grp;do
if [ ! -z "$(ldapsearch -w 'ldappass' -D "cn=adminuser,dc=some-domain,dc=com" -b "cn=$grp,ou=group,dc=some-domain,dc=com" | grep $someuser)" ]; then
remove $someuser
fi
done < /home/someuser/tempfile.txt

Bash programming with filesystem functions

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

Resources