Creating an SQL file in BASH - mysql

I am trying to create an sql script using bash but I keep getting this line after each iteration of my loop
: command not found
This is the case on Ubuntu as well as OSX.
At this stage I am not executing the sql script, I simply trying to create it. What am I missing so that it will not try to "execute" the query?
The queries are fine when tested in phpmyadmin
I don't understand why would need to set the $PATH variable if I am not executing the actual query, I am just creating the text file.
The code I use is:
SQL="";
cat people.txt | while read line
do
PW="my"$line"db";
DB="test_"$line;
$SQL=$SQL"CREATE DATABASE \`$DB\`;CREATE USER \`$line\`#\`localhost\`;SET PASSWORD FOR \`$line\`#\`localhost\` = PASSWORD(\"$PW\") ;GRANT ALL PRIVILEGES ON $DB.* TO \`$line\`#\`localhost\` IDENTIFIED BY \"$PW\";";
done
echo $SQL > t1.sql;
The list I am using for my imports:
bob123
john123
jane123
The output I am getting is:
./02_setup_mysqldb.sh: line 14: =CREATE DATABASE `test_bob123`;CREATEUSER `bob123`#`localhost`;SET PASSWORD FOR `bob123`#`localhost` = PASSWORD("mybob123db") ;GRANT ALL PRIVILEGES ON test_bob123.* TO `bob123`#`localhost` IDENTIFIED BY "mybob123db";: command not found
./02_setup_mysqldb.sh: line 14: =CREATE DATABASE `test_john123`;CREATE USER `john123`#`localhost`;SET PASSWORD FOR `john123`#`localhost` = PASSWORD("myjohn123db") ;GRANT ALL PRIVILEGES ON test_john123.* TO `john123`#`localhost` IDENTIFIED BY "myjohn123db";: command not found

There's an error in your variable assignment, it should be:
SQL=$SQL"CREATE DATABASE...
Note the missing $ in front of the variable name - variables don't need $ in front of the name when values are assigned.

Notes:
1.The assignment to SQL variable is incorrect, just change to SQL="$SQL...", just remove the $ character.
2.When you do cat people.txt | while read LINE, you are ignoring the last line, being necessary to have a blank line after the last line.
3.Your script has a large string concatenation in one line, just create variables to make it more readable.
Finally, code:
#!/bin/bash
while read line
do
PW="my${line}db"
DB="test_$line"
create_database="CREATE DATABASE \`$DB\`;\n"
create_user="CREATE USER \`$line\`#\`localhost\`;\n"
change_password="SET PASSWORD FOR \`$line\`#\`localhost\` = PASSWORD(\"$PW\");\n"
grant_privileges="GRANT ALL PRIVILEGES ON $DB.* TO \`$line\`#\`localhost\` IDENTIFIED BY \"$PW\";\n"
SQL="${SQL}${create_database}${create_user}${change_password}${grant_privileges}"
done < people.txt
echo -e ${SQL} > t1.sql

Related

Mysql query to update multiple rows using a input file from linux

I'm trying to update multiple rows in a DB using a small script.
I need to update the rows based on some specific user_ids which I have in a list on Linux machine.
#! /bin/bash
mysql -u user-ppassword db -e "update device set in_use=0 where user_id in ()";
As you see above, the user_ids are in a file, let's say /opt/test/user_ids_txt.
How can I import them into this command?
This really depends on the format of user_ids_txt. If we assume it just happens to be in the correct syntax for your SQL in statement, the following will work:
#! /bin/bash
mysql -u user-ppassword db -e "update device set in_use=0 where user_id in ($(< /opt/test/user_ids_txt))";
The bash interpreter will substitute in the contents of the file. This can be dangerous for SQL queries, so I would echo out the command on the terminal to make sure it is correct before implementing it. You should be able to preview your SQL query by simply running the following on the command line:
echo "update device set in_use=0 where user_id in ($(< /opt/test/user_ids_txt))"
If your file is not in the SQL in syntax you will need to edit it (or a copy of it) before running your query. I would recommend something like sed for this.
Example
Let's say your file /opt/test/user_ids_txt is just a list of user_ids in the format:
aaa
bbb
ccc
You can use sed to edit this into the correct SQL syntax:
sed 's/^/\'/g; s/$/\'/g; 2,$s/^/,/g' /opt/test/user_ids_txt
The output of this command will be:
'aaa'
,'bbb'
,'ccc'
If you look at this sed command, you will see 3 separate commands separated by semicolons. The individual commands translate to:
1: Add ' to the beginning of every line
2: Add ' to the end of every line
3: Add , to the beginning of every line but the first
Note: If your ID's are strictly numeric, you only need the third command.
This would make your SQL query translate to:
update device set in_use=0 where user_id in ('aaa'
,'bbb'
,'ccc')
Rather than make a temporary file to store this, I would use a bash variable, and simply plug that into the query like this:
#! /bin/bash
in_statement="$(sed 's/^/\'/g; s/$/\'/g; 2,$s/^/,/g' /opt/test/user_ids_txt)"
mysql -u user-ppassword db -e "update device set in_use=0 where user_id in (${in_statement})";

SQL Errors using like and %

My script is designed to cycle through environments, hit a database and check to see if any first/last name combination has an associated user ID. I am not sure why I'm getting the error listed below.
#/bin/bash
#specify user to search for *******DO NOT PUT SPACE, ie. jaylefler
echo "Please enter user first name: "
read first_name
echo "Please enter user last name: "
read last_name
echo "Please enter LDAP User ID: "
read ldapuser
echo "Please enter LDAP password: "
stty -echo
read ldappw
stty echo
#logs to write output to
log="ui_${username}_access.log"
finallog="${username}_ui_access.txt"
#create file if not exist, else null it
[[ -f ${log} ]] && cat /dev/null > ${log} || touch ${log}
[[ -f ${finallog} ]] && cat /dev/null > ${finallog} || touch ${log}
#log it all
{
echo "environment"
sshpass -p $ldappw ssh $ldapuser#54.123.777.567 'mysql -h host -u user - ppassword database -e \
"select user_id from users where first like "%'${first_name}'%" and last like "%'${last_name}'%";"'
} > $log
When I execute the script, I receive the following errors:
Please enter user first name:
jay
Please enter user last name:
lefler
Please enter LDAP User ID:
jlefler
Please enter LDAP password:
ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%jay% and last like %lefler%' at line 1
jlefler#ubuntu:~/Desktop$
I'm not that familiar with this type of scripting, but it would seem to me that around %jay% and %lefler% there would need to be quotations so that the SQL appears as:
select user_id from users where first like '%jay%' and last like '%lefler%';
The primary problem in your code is that the quotation marks are inside of the percent signs. :)
The second problem is that you have created something that is vulnerable to SQL injection. I have absolutely no idea how to create bound parameters from a Bash script, but you need to figure that out!
The query to MySQL is supposed to output something like this:
SELECT * FROM pet WHERE name LIKE '%w%';
In bash one of the way to concatenate is as follow:
mystring="some ${string1} arbitrary ${string2} text"
EDIT:
So combining all Plus making somethin to expand the strings inside ''. The problem is that shell Can not expand strings between single quotations marks.
Something like this should work:
CommandFinale=$($sqlCommand -e "select user_id from users where first like '%${first_name}%' and last like '%${last_name}%';")
Then use the variable CommandFinale in you connection chain.
I have not bee able to test it but it should be like that or very similar.

Need to display alternative text when query results return no match

My script cycles through multiple environments and if a user is found, it prints out their ID. The desired output is as follows:
environment1
<user_id>
However, my script is currently working to print out every environment even if there isn't a user id, like follows:
environment1
<user_id>
environment2
environment3
environment4
<user_id>
I would like the code to print out "NO USER FOUND" if the user_id does not exist, rather than excluding the environment altogether.
The code below is what is being utilized:
#log it all
{
echo "environment"
sshpass -p $ldappw ssh $ldapuser#12.345.67.89 'mysql --skip-column-names -hhost -u user -ppassword database -e \
"select user_id from users where first like '"'%${first_name}%' and last like '%${last_name}%';"'"'
} > $log
Any help would be much appreciated for this issue. Unfortunately I'm just beginning to learn more advanced MySQL and Linux command line tools and am not quite proficient enough to know how to handle this problem.
may be
select ifnull(user_id,'NO USER FOUND') from users where first like '"'%${first_name}%' and last like '%${last_name}%';

Can MySQL check that file exists?

I have a table that holds relative paths to real files on HDD. for example:
SELECT * FROM images -->
id | path
1 | /files/1.jpg
2 | /files/2.jpg
Can I create a query to select all records pointing to non-existent files? I need to check it by MySql server exactly, without using an iteration in PHP-client.
I would go with a query like this:
SELECT id, path, ISNULL(LOAD_FILE(path)) as not_exists
FROM images
HAVING not_exists = 1
The function LOAD_FILE tries to load the file as a string, and returns NULL when it fails.
Please notice that a failure in this case might be due to the fact that mysql simply cannot read that specific location, even if the file actually exists.
EDIT:
As #ostrokach pointed out in comments, this isn't standard SQL, even though MySQL allows it, to follow the standard it could be:
SELECT *
FROM images
WHERE LOAD_FILE(PATH) IS NULL
The MySQL LOAD_FILE command has very stringent requirements on the files that it can open. From the MySQL docs:
[LOAD_FILE] Reads the file and returns the file contents as a string. To use this function, the file must be located on the server host, you must specify the full path name to the file, and you must have the FILE privilege. The file must be readable by all and its size less than max_allowed_packet bytes. If the secure_file_priv system variable is set to a non-empty directory name, the file to be loaded must be located in that directory.
So if the file can't be reached by the mysql user or any of the other requirements are not satisfied, LOAD_FILE will return Null.
You can get a list of IDs that correspond to missing files using awk:
mysql db_name --batch -s -e "SELECT id, path FROM images" \
| awk '{if(system("[ -e " $2 " ]") == 1) {print $1}}' \
>> missing_ids.txt
or simply using bash:
mysql db_name --batch -s -e "SELECT id, path FROM images" \
| while read id path ; if [[ -e "$path" ]] ; then echo $id ; done
>> missing_ids.txt
This also has the advantage of being much faster than LOAD_FILE.
MYSQL only handles the Database so there is no way for you to fire an SQL Statement to check on the HDD if the file exists. You need to iterate over the rows and check it with PHP.
It's not possible using stock MySQL. However you can write UDF (user-defined function), probably in C, load it using CREATE FUNCTION statement and use it from MySQL as you would use any built-in function.

Using shell script to insert data into remote MYSQL database

I've been trying to get a shell(bash) script to insert a row into a REMOTE database, but I've been having some trouble :(
The script is meant to upload a file to a server, get a URL, HASH, and a file size, connect to a remote mysql database, and insert the data into an existing table. I've gotten it working until the remote MYSQL database bit.
It looks like this:
#!/bin/bash
zxw=randomtext
description=randomtext2
for file in "$#"
do
echo -n *****
ident= *****
data= ****
size=` ****
hash=`****
mysql --host=randomhost --user=randomuser --password=randompass randomdb
insert into table (field1,field2,field3) values('http://www.example.com/$hash','$file','$size');
echo "done"
done
I'm a total noob at programming so yeah :P
Anyway, I added the \ to escape the brackets as I was getting errors. As it is right now, the script is works fine until connects to the mysql database. It just connects to the mysql database and doesn't do the insert command (and I don't even know if the insert command would work in bash).
PS: I've tried both the mysql commands from the command line one by one, and they worked, though I defined the hash/file/size and didn't have the escaping "".
Anyway, what do you guys think? Is what I'm trying to do even possible? If so how?
Any help would be appreciated :)
The insert statement has to be sent to mysql, not another line in the shell script, so you need to make it a "here document".
mysql --host=randomhost --user=randomuser --password=randompass randomdb << EOF
insert into table (field1,field2,field3) values('http://www.site.com/$hash','$file','$size');
EOF
The << EOF means take everything before the next line that contains nothing but EOF (no whitespace at the beginning) as standard input to the program.
This might not be exactly what you are looking for but it is an option.
If you want to bypass the annoyance of actually including your query in the sh script, you can save the query as .sql file (useful sometimes when the query is REALLY big and complicated). This can be done with simple file IO in whatever language you are using.
Then you can simply include in your sh scrip something like:
mysql -u youruser -p yourpass -h remoteHost < query.sql &
This is called batch mode execution. Optionally, you can include the ampersand at the end to ensure that that line of the sh script does not block.
Also if you are concerned about the same data getting entered multiple times and your rdbms getting inconsistent, you should explore MySql transactions (commit, rollback, etc).
Don't use raw SQL from bash; bash has no sane facility for sanitizing the data beforehand. Generate a CSV file and upload that instead.