MySQL password input in bash script - mysql

I have a bash script that needs to perform a couple actions in MySQL. So far I have something like this:
#!/bin/sh
read -p "Enter your MySQL username: " $sqluname
read -sp "Enter your MySQL password (ENTER for none): " $sqlpasswd
/usr/bin/mysql -u $sqluname -p $sqlpasswd << eof
*some SQL stuff*
eof
This works well until it's used with a MySQL username that has a blank password. The user hits ENTER at my password prompt, but then they receive another prompt to "Enter your password" again from MySQL.
How can I avoid this second password prompt and make the script deal with both blank and non-blank passwords?

Check if the password is blank or not, and if it is, then omit the -p switch altogether.
read -p "Enter your MySQL username: " $sqluname
read -sp "Enter your MySQL password (ENTER for none): " $sqlpasswd
if [ -n "$sqlpasswd" ]; then
/usr/bin/mysql -u $sqluname -p $sqlpasswd << eof
else
/usr/bin/mysql -u $sqluname << eof
fi
Later edit to avoid a whole if-then-else block:
command="/usr/bin/mysql -u $sqluname"
[ -n "$sqlpasswd" ] && command="$command -p$sqlpasswd"
eval $command

You'd need to specify the -n switch if $sqlpasswd is empty (instead of -p $sqlpasswd).

Related

How to take all database backup same as db name

I am using MySQL on centos7. I have 50 databases Like database1, database2...., database50.
How can I set a cronjob for take a dump every day of all database same as database name [ Like database1.sql, database2.sql .... database50.sql ] using single command or script.
Please provide some adequate solution that will be appreciated.
Thanks.
Convert the current date to an integer number of days since some starting date.
Take that modulo 50. This gives you 0 .. 49.
Add 1 and concatenate. Now you have database1 .. database50. Put that in the shell variable db
mysqldump ... $db >$db.sql
I am using this script
#! /bin/bash
# MySQL database backup (databases in separate files) with daily, weekly and monthly rotation
# Sebastian Flippence (http://seb.flippence.net) originally based on code from: Ameir Abdeldayem (http://www.ameir.net)
# You are free to modify and distribute this code,
# so long as you keep the authors name and URL in it.
# Modified by IVO GELOV
# How many backups do you want to keep?
MAX_DAYS=5
# Date format that is appended to filename
DATE=`date +'%Y-%m-%d'`
DATSTR=`date '+%Y%m%d' -d "-$MAX_DAYS days"`
# MySQL server's name
SERVER=""
# Directory to backup to
BACKDIR="/var/db_arhiv/mysql"
#----------------------MySQL Settings--------------------#
# MySQL server's hostname or IP address
HOST="localhost"
# MySQL username
USER="user"
# MySQL password
PASS="password"
# List all of the MySQL databases that you want to backup,
# each separated by a space. Or set the option below to backup all database
DBS="db1 db2"
# Set to 'y' if you want to backup all your databases. This will override
# the database selection above.
DUMPALL="y"
# Custom path to system commands (enable these if you want use a different
# location for PHP and MySQL or if you are having problems running this script)
MYSQL="/usr/local/mysql/bin/mysql"
MYSQLDUMP="/usr/local/mysql/bin/mysqldump"
function checkMysqlUp() {
$MYSQL -N -h $HOST --user=$USER --password=$PASS -e status > /dev/null
}
trap checkMysqlUp 0
function error() {
local PARENT_LINENO="$1"
local MESSAGE="$2"
local CODE="${3:-1}"
if [[ -n "$MESSAGE" ]] ; then
echo "Error on or near line ${PARENT_LINENO}: ${MESSAGE}; exiting with status ${CODE}"
else
echo "Error on or near line ${PARENT_LINENO}; exiting with status ${CODE}"
fi
exit "${CODE}"
}
trap 'error ${LINENO}' ERR
# Check backup directory exists
# if not, create it
if [ ! -e "$BACKDIR/$DATE" ]; then
mkdir -p "$BACKDIR/$DATE"
echo "Created backup directory (${BACKDIR}/${DATE})"
fi
if [ $DUMPALL = "y" ]; then
echo "Creating list of databases on: ${HOST}..."
$MYSQL -N -h $HOST --user=$USER --password=$PASS -e "show databases;" > ${BACKDIR}/dbs_on_${SERVER}.txt
# redefine list of databases to be backed up
DBS=`sed -e ':a;N;$!ba;s/\n/ /g' -e 's/Database //g' ${BACKDIR}/dbs_on_${SERVER}.txt`
fi
echo "Backing up MySQL databases..."
#cd ${LATEST}
for database in $DBS; do
if [ ${database} = "information_schema" ] || [ ${database} = "performance_schema" ] || [ ${database} = "pinba" ]
then
continue
fi
echo "${database}..."
$MYSQLDUMP --host=$HOST --user=$USER --password=$PASS --default-character-set=utf8 --routines --triggers --lock-tables --disable-keys --force --single-transaction --allow-keywords --dump-date $database > ${BACKDIR}/${DATE}/${SERVER}$database.sql
done
if [ $DUMPALL = "y" ]; then
rm -f ${BACKDIR}/dbs_on_${SERVER}.txt
fi
# dump privileges
$MYSQL -N -h $HOST --user=$USER --password=$PASS --skip-column-names -A -e "SELECT CONCAT('SHOW GRANTS FOR ''',user,'''#''',host,''';') FROM mysql.user" | $MYSQL -N -h $HOST --user=$USER --password=$PASS --skip-column-names -A > ${BACKDIR}/${DATE}/${SERVER}_grants.sql
# delete older files
for x in `find ${BACKDIR}/20* -type d`
do
xd=`basename "${x//-/}"`
if [[ $xd < $DATSTR ]]
then
rm -rf "$x"
fi
done
echo "MySQL backup is complete"

Bash - Break up returned value from MySQL query

I am trying to break up a returned value from a mysql call in a shell script. Essentially what I have done so far is query the database for IP addresses that I have stored in a specific table. From there I store that returned value into a bash variable. The code is below:
#!/bin/bash
# This file will be used to obtain the system details for given ip address
retrieve_details()
{
# get all the ip addresses in the hosts table to pass to snmp call
host_ips=$(mysql -u user -ppassword -D honours_project -e "SELECT host_ip FROM hosts" -s)
echo "$host_ips"
# break up the returned host ip values
# loop through array of ip addresses
# while [ ]
# do
# pass ip values to snmp command call
# store details into mysql table host_descriptions
# done
}
retrieve_details
So this returns the following:
192.168.1.1
192.168.1.100
192.168.1.101
These are essentially the values I have in my hosts table. So what I am trying to do is break up each value such that I can get an array that looks like the following:
arr[0]=192.168.1.1
arr[1]=192.168.1.100
arr[2]=192.168.1.101
...
I have reviewed this link here: bash script - select from database into variable but I don't believe this applies to my situation. Any help would be appreciated
host_ips=($(mysql -u user -ppassword -D honours_project -e "SELECT host_ip FROM hosts" -s));
outer () will convert that in array. But you need to change your IFS (Internal Field Separator) to a newline first.
IFS=$'\n';
host_ips=($(mysql -u user -ppassword -D honours_project -e "SELECT host_ip FROM hosts" -s));
unset IFS;
for i in ${host_ips[#]} ; do echo $i ; done;
to print with key
for i in "${!host_ips[#]}"
do
echo "key :" $i "value:" ${host_ips[$i]}
done
wspace#lw:~$ echo $host_ips
192.168.1.1 192.168.1.100 192.168.1.101
wspace#lw:~$ arr=($(echo $host_ips))
wspace#lw:~$ echo ${arr[0]}
192.168.1.1
wspace#lw:~$ echo ${arr[1]}
192.168.1.100
wspace#lw:~$ echo ${arr[2]}
192.168.1.101
wspace#lw:~$ echo ${arr[#]}
192.168.1.1 192.168.1.100 192.168.1.101
wspace#lw:~$
maybe this is what you want

Bash: testing if executed command was succesfull

I have the following script:
if [ `mysql -u root -p < test.sql` ]; then
echo "success"
else
echo "some error"
fi
How can I check in the if if the command went well or there was some sql error?
You don't need the test command, i.e. [ here.
Assuming that mysql produces a non-zero exit code in case of failure and 0 on success, then you can say:
if mysql -u root -p < test.sql; then
echo "success"
else
echo "some error"
fi
Another way this is typically done is with the "&&" and "||" separators. For example:
mysql -u root -p < test.sql && echo "success" || echo "some error"
If the mysql command exits with status 0, then "success" will be printed. If it doesn't, "some error" will be printed.

DATABASE autocreation bash script: What's wrong?

My bash script won't crate the Database. What am I doing wrong here?
Please have a look:
#!/bin/bash -x
set -x
function deebee() {
EXPECTED_ARGS=2
E_BADARGS=65
MYSQL=`which mysql`
Q1="CREATE DATABASE IF NOT EXISTS $1;"
Q2="GRANT USAGE ON *.* TO $2#localhost IDENTIFIED BY '$3';"
Q3="GRANT ALL PRIVILEGES ON $1.* TO $2#localhost;"
Q4="FLUSH PRIVILEGES;"
SQL="${Q1}${Q2}${Q3}${Q4}"
if [ $# -ne $EXPECTED_ARGS ]
then
echo "Usage: $0 dbname dbuser dbpass"
exit $E_BADARGS
fi
$MYSQL -uroot -p -e "$SQL"
}
deebee $1 $2 $3
I'm calling the script as I've put it in a function, but it just spits out the expected arguments telling me the syntax, i.e that I should type in the bashscrip name, dbname, dbuser dbpass, but obviously there' something wrong with the script of my login permissions or user so that I can't automate this... What's going on, I'd love to know!
Thanks!
What I would do :
creating a mysql config file with credentials (easier to automate now) :
cat ~/.my.cnf
[client]
host = localhost
user = root
password = xxx
And the script :
#!/bin/bash
set -x
deebee() {
EXPECTED_ARGS=3
E_BADARGS=65
MYSQL=$(type -p mysql)
if (($# != $EXPECTED_ARGS))
then
echo "Usage: $0 dbname dbuser dbpass"
exit $E_BADARGS
fi
$MYSQL <<EOF
CREATE DATABASE IF NOT EXISTS '$1';
GRANT USAGE ON *.* TO '$2'#'localhost' IDENTIFIED BY '$3';
GRANT ALL PRIVILEGES ON '$1'.* TO '$2'#'localhost';
FLUSH PRIVILEGES;
EOF
}
# TODO tests on input args
deebee "$1" "$2" "$3"
And like Denis said in comments, take care of what users can put as arguments to prevent sql injection.
You should add some tests on input args.

How to run MySQL command on bash?

The following code works on the command line
mysql --user='myusername' --password='mypassword' --database='mydatabase' --execute='DROP DATABASE myusername;
CREATE DATABASE mydatabase;'
However, it doesn't work on bash file on execution
#!/bin/bash
user=myusername
password=mypassword
database=mydatabase
mysql --user='$user' --password='$password' --database='$database' --execute='DROP DATABASE $user; CREATE DATABASE $database;'
I receive the following error:
ERROR 1045 (28000): Access denied for user '$user'#'localhost' (using password: YES)
How to make the bash file run as the command line?
Use double quotes while using BASH variables.
mysql --user="$user" --password="$password" --database="$database" --execute="DROP DATABASE $user; CREATE DATABASE $database;"
BASH doesn't expand variables in single quotes.
This one worked, double quotes when $user and $password are outside single quotes. Single quotes when inside a single quote statement.
mysql --user="$user" --password="$password" --database="$user" --execute='DROP DATABASE '$user'; CREATE DATABASE '$user';'
I have written a shell script which will read data from properties file and then run mysql script on shell script. sharing this may help to others.
#!/bin/bash
PROPERTY_FILE=filename.properties
function getProperty {
PROP_KEY=$1
PROP_VALUE=`cat $PROPERTY_FILE | grep "$PROP_KEY" | cut -d'=' -f2`
echo $PROP_VALUE
}
echo "# Reading property from $PROPERTY_FILE"
DB_USER=$(getProperty "db.username")
DB_PASS=$(getProperty "db.password")
ROOT_LOC=$(getProperty "root.location")
echo $DB_USER
echo $DB_PASS
echo $ROOT_LOC
echo "Writing on DB ... "
mysql -u$DB_USER -p$DB_PASS dbname<<EOFMYSQL
update tablename set tablename.value_ = "$ROOT_LOC" where tablename.name_="Root directory location";
EOFMYSQL
echo "Writing root location($ROOT_LOC) is done ... "
counter=`mysql -u${DB_USER} -p${DB_PASS} dbname -e "select count(*) from tablename where tablename.name_='Root directory location' and tablename.value_ = '$ROOT_LOC';" | grep -v "count"`;
if [ "$counter" = "1" ]
then
echo "ROOT location updated"
fi