Execution of dynamic mysql query fails - mysql

In a recent bash script, I required a function to standardize calls to a mysql server. My first version of the function looked like this:
mysqlfunc()
{
args="-A"
if [ "$1" = "++" ]; then
shift
while [ 1 ]; do
if [ "$1" = "--" ]; then
shift
break
fi
args="$args $1"
shift
done
fi
query="-e \"$*\""
if [ -f "$1" ]; then
query="< $1"
fi
mysql $args -h<host> -p<password> -P<port> -u<user> <database> $query
}
This version of the function produced a syntactically correct mysql statement; executing the evaluated command on the command line worked without error. However, when a file was passed to the function, such as:
mysqlfunc $DB_Scripts/mysql_table_create.sql
The mysql command would fail, complaining of what appeared to be either incorrect arguments supplied or incorrect syntax. It didn't specify which, only printed the usage help for mysql.
My question: Why does this dynamic statement assignment fail?
Example:
Function call:
mysqlcmd $PATH_TO_FILE/example.sql
Mysql command executed:
mysql -A -h<host> -p<password> -P<port> -u<user> <database> < <path_to_file>/example.sql
Result:
Usage for mysql printed to the terminal

You can't put shell metacharacters like < inside variables and have them function.
That's not how the parser works. The shell doesn't see the < in the variable result as a redirection operator it sees it as a literal string.
This is part of what Bash FAQ 050 covers.

can you do something like
if [ -f "$1" ]; then
cat $1 | mysql $args -h<host> -p<password> -P<port> -u<user> <database>
else
mysql $args -h<host> -p<password> -P<port> -u<user> <database> $query
fi
works with psql

Related

How to check if a table exists in a MySQL database using shell script?

i am trying to check whether a table is empty or not using shell script
the code that i have is
#!/bin/bash
if [ "mysql -u user -ppassword -hserver dbname -e 'select count(*) from test_dec;'" != 0 ];
then
echo "table not empty"
else
echo "table empty"
fi
but when i run this it always displays "table not empty" even if the output of the query is 0.
user#server$ ./table_check.sh
table not empty
what is wrong here?
This is my version of the script and it will first check if table exists and if yes will check if the table is empty.
BASH
#!/bin/bash
# Prepare variables
TABLE=$1
SQL_EXISTS=$(printf 'SHOW TABLES LIKE "%s"' "$TABLE")
SQL_IS_EMPTY=$(printf 'SELECT 1 FROM %s LIMIT 1' "$TABLE")
# Credentials
USERNAME=YOUR_USERNAME
PASSWORD=YOUR_PASSWORD
DATABASE=YOUR_DATABASE_NAME
echo "Checking if table <$TABLE> exists ..."
# Check if table exists
if [[ $(mysql -u $USERNAME -p$PASSWORD -e "$SQL_EXISTS" $DATABASE) ]]
then
echo "Table exists ..."
# Check if table has records
if [[ $(mysql -u $USERNAME -p$PASSWORD -e "$SQL_IS_EMPTY" $DATABASE) ]]
then
echo "Table has records ..."
else
echo "Table is empty ..."
fi
else
echo "Table not exists ..."
fi
USAGE
First before using this script you need to replace YOUR_USERNAME, YOUR_PASSWORD and YOUR_DATABASE_NAME with the corresponding values. Then:
# bash SCRIPT_NAME TABLE_TO_CHECK
bash my_script my_table
where SCRIPT_NAME( my_script ) is the name of the file holding the above script content and TABLE_TO_CHECK( my_table ) is the name of the table that you want to check for.
EXPECTED OUTPUT
Checking if table <my_table> exists ...
Table exists ...
Table is empty ...
COUPLE OF WORDS ABOUT THE CODE
Store the first argument from the command line in variable TABLE
TABLE=$1
Prepare two variables that will hold the SQL queries used to check.
Note that printf is used to insert the table name in the variables, because $('SHOW TABLES LIKE "$TABLE"') is not going to work.
SQL_EXISTS=$(printf 'SHOW TABLES LIKE "%s"' "$TABLE")
SQL_IS_EMPTY=$(printf 'SELECT COUNT(*) as records FROM %s' "$TABLE")
Check if table exists. SHOW TABLES LIKE "table_name" will return empty string if the table does not exist and the if statement will fail. Usage of the $ like $(echo 1 + 2) means - evaluate whatever is inside the parentheses and return that as a value.
if [[ $(mysql -u $USERNAME -p$PASSWORD -e "$SQL_EXISTS" $DATABASE) ]]
Finally we check if table is empty. Using the previous approach. Basically we check if MySQL will return empty string (for empty tables), otherwise the query will return some text as a result and we can consider the table not empty.
if [[ $(mysql -u $USERNAME -p$PASSWORD -e "$SQL_IS_EMPTY" $DATABASE) ]]
This should work
if [ $(mysql -u root -p -e \
"select count(*) from information_schema.tables where \
table_schema='db_name' and table_name='table_name';") -eq 1 ]; then
echo "table exist"
exit 1
else
echo "table doesn't exist"
exit 1
fi
I think below will do your work,
#!/bin/bash
if [ $(mysql -u user -ppassword -hserver dbname -sse "select count(*) from test_dec;") -gt 0 ];
then
echo "table not empty"
else
echo "table empty"
fi
3 changes from your script,
enclose whole mysql statement part inside $(..) --> to make LHS the result of what goes inside $(...)
change -e to -sse in mysql connection statement --> to get only result of query to output without header and table structure.
Change != to -gt --> operator for integer comparison in bash
This works for me when testing if we need to re-import a database.
databasename="mydatabasename";
tablename="tableweneed";
dbhost="localhost";
username="user";
password="password";
dbtest=$(mysql -h ${dbhost} -u ${username} -p${password} -s -N -e "select count(*) as tablecount from information_schema.tables WHERE table_schema='${databasename}' and table_name='${tablename}'")
if [ "$dbtest" == 1 ]; then
echo "Database is ok"
else
echo "Database is being re-imported"
mysql -h ${dbhost} -u ${user} -p${password} ${databasename} < /somefolderonmysystem/importdb.sql
fi
After trying a few different methods, this is what we used:
if [[ $(mysql --execute "SHOW TABLES FROM ${DB_NAME} LIKE '${DB_PREFIX}options';") -gt 0 ]]; then
...and yes, we define mysql as a function earlier in the script, and the database name and database prefix are also defined in a configuration file (this is part of our SlickStack project).
function mysql {
command mysql --user=root --host=localhost --protocol=socket --port=3306 --force "$#"
}
You can change the name of this function in your bash script as desired.
Example: https://github.com/littlebizzy/slickstack/blob/master/bash/ss-install-wordpress-config.txt

UNIX SHELL SCRIPT - MYSQL issue

Below Unix shell script fails saying unexpected end of file at the mysql line before $selectg line. Not sure what mistake i am doing. Provided part of script below. Could anyone help me out.
#!/bin/bash
ip="77.299.113.81"
pass="-ptest123"
read -d '' selectg <<EOGG SELECT * FROM agstatus ; EOGG
for row in `mysql -h $ip -u root $pass "ruttt" -e "SELECT databasename FROM master.customers"`; do
rownum=$((rownum+1))
echo "Row:$row"
if [ $rownum -ne 1 ]; then
mysql -u tsadm -p'test123' -h 77.299.113.81 Csfgat << eof
$selectg
eof
fi
done
echo "done"
The end token of a here document has to be on a line by itself:
read -d '' selectg <<EOGG
SELECT * FROM agstatus;
EOGG
Alternatively, you can use a here string:
read -d '' selectg <<< "SELECT * FROM agstatus;"
Or in your specific case, a plain ol' assignment:
selectg="SELECT * FROM agstatus;"

How to write a bash function to wrap another command?

I am trying to write a function wrapper for the mysql command
If .my.cnf exists in the pwd, I would like to automatically attach --defaults-file=.my.cnf to the command
Here's what I'm trying
function mysql {
if [ -e ".my.cnf" ]; then
/usr/local/bin/mysql --defaults-file=.my.cnf "$#"
else
/usr/local/bin/mysql "$#"
fi
}
The idea is, I want to be able to use the mysql command exactly as I was before, only, if the .my.cnf file is present, attach it as an argument
Question: Will I run into any trouble with this method? Is there a better way to do it?
If I specify --defaults-file=foo.cnf manually, that should be used instead of .my.cnf.
Your function as written is perfectly fine. This is a touch DRYer:
function mysql {
if [ -e ".my.cnf" ]; then
set -- --defaults-file=.my.cnf "$#"
fi
/usr/local/bin/mysql "$#"
}
That set command puts your my.cnf argument at the beginning of the command line arguments
Only if the option is not already present:
function mysql {
if [[ -e ".my.cnf" && "$*" != *"--defaults-file"* ]]; then
set -- --defaults-file=.my.cnf "$#"
fi
/usr/local/bin/mysql "$#"
}

How to use select statement result as a variable and pass it further to the script

please advise how to use select statement result as a variable and pass it further to the script. Simple script:
#!/bin/sh
# --mysql part START--
pwd="pass"
D="db"
mysql -uuser -p$pwd -D$D -s -N -e "SELECT port FROM table where username='$1';"
/usr/bin/mysql -uroot -p$pwd -D$D<< eof
eof
port=$(mysql Select) # declaring select result as a variable , probably wrong
echo "port $port;" >> /tmp/blabla.txt # <- this part is not working
Please advise.
Thanks in advance
You can put it into an a variable, follow this example:
#!/bin/sh
# --mysql part START--
pwd="pass"
D="db"
user="user"
port=$(mysql -u $user -p $pwd -D $D -s -N -e "SELECT port FROM table where username='$1';")
echo "PORT: $port" > /tmp/blabla.txt

Shell script if condition

I'm writing a script which runs the following command
mysql -u root -e "show databases"
and this will display a list of databases.
If this table doesn't contain a database by name "userdb", it should do the following-
if [ ... ]; then
echo "error"
exit
fi
What do i write in the if [ ... ] condition?
You can check with grep if the table name is listed. grep -q will not print anything to the console but will set the exit status according to the result (the exit status will then be checked by if).
if ! mysql -u root -e 'show databases' | grep -q '^userdb$' ; then
echo error
exit
fi
About the regular expression: '^' matches the beginning of the line and '$' matches the end of the line (to avoid a false positive for database names containing userdb, e.g. userdb2)
Try this one:
usedb=DBname
check=`mysql -u root -e "show databases" | grep $userdb`
if [ "$check" != "$userdb" ]; then
echo "error"
exit
fi
But here will be an error if line with database name contain any other information.
Try to workaround it with regexp