6

I just cant do it. If * is in a variable, it expands to a list of files in current folder. echo "*" works fine.

#!/bin/bash
c="GRANT ALL ON \*.* TO '$1'@'localhost';"
mysql < $c
exit 0;
6

Use single quotes for your string:

c='GRANT ALL ON *.* TO';
c="${c} '$1'@'localhost';";

There is probably a better way to do that but including $1 in the string made it weird

  • 3
    This isn't the problem at all -- wildcards don't get expanded inside double-quotes either, so (other than removing the backslash) this is the same as what the question had. The real problem is how c is used, not how it's defined. See Gilles, slillibri, and Dennis Williamson's answers for more relevant solutions. – Gordon Davisson Jul 25 '10 at 1:14
8
  1. Always put double quotes around variable substitutions, otherwise characters like spaces and * appearing in the value are interpreted by the shell. I.e., write "$c", not $c.

  2. The syntax mysql <"$c" makes mysql execute commands from a file whose name is the value of $c. What you're looking for is

    printf '%s\n' "$c" | mysql
    

    or simpler, as long as you remember the restrictions ($c must not start with a -, and if it contains \ that's ok in bash but not in some other variants of sh)

    echo "$c" | mysql
    

    There's another alternative that's more comfortable if the command is multiline. It's called a “here-document”. The string EOF isn't special (though it's traditional), any sequence of letters and digits will do. The terminating EOF may not be preceded by whitespace. You need to put a \ before every $, \ and ` unless you want them interpreted by the shell.

    mysql <<EOF
    GRANT ALL ON *.* TO '$1'@'localhost';
    EOF
    
  3. Beware that if the argument to the shell contains a single quote, you have an injection vector. The following snippet adds a \ before every \ and '.

    set -- "${1//\\/\\\\}"
    set -- "${1//\'/\'}"
    

    This is fairly ugly, which is why if you're going to do anything complicated, forget about using a shell and use a language with actual SQL bindings (perl, python, whatever) where the library handles all the quoting and procedure building for you.

2

This will work in bash, no escaping necessary

#!/bin/bash
mysql -u root -e "GRANT ALL ON *.* TO '$1'@'localhost'"
exit 0;
1

First you need to print the SQL command using echo.

Then you need to put quotes around $c like so:

mysql <( echo "$c" )

Otherwise the value of $c will be treated as a bash command and thus, the * will be expanded.

Or a simpler version could be:

mysql -e "$c"
1

It's no more complicated than this:

#!/bin/bash
c="GRANT ALL ON *.* TO $1@localhost;"
mysql -e "$c"

Or, if you need the single quotes:

#!/bin/bash
c="GRANT ALL ON *.* TO '$1'@'localhost';"
mysql -e "$c"
1

Simple is perfect! (quote the first part with single quote)

#!/bin/bash
c='GRANT ALL ON *.*' "TO '$1'@'localhost';"
mysql < $c
exit 0;

it should be perfect too! ($c quoted)

#!/bin/bash
c="GRANT ALL ON *.* TO '$1'@'localhost';"
mysql < "$c"
exit 0;
  • Will this not treat $c as a file name – Rohit Banga Oct 1 '13 at 23:51
0

The feature fighting you is shell globbing as part of pathname expansion. Disable this to solve the primary problem you reported. Then use Weboide's suggestion of -e to execute a single command contained in the $c variable through Mysql. Cheers,

[maxwell@elite ~]$ cat me.sh
#!/bin/bash

# disable shell globbing so c variable can be literal
set -f
c="GRANT ALL ON *.* TO '$1'@'localhost';"

echo $c

# enable shell globbing for normal operation
set +f
echo $c
[maxwell@elite ~]$ ./me.sh maxwell
GRANT ALL ON *.* TO 'maxwell'@'localhost';
GRANT ALL ON labserver.etc.0710.tar me.sh Validation.txt TO 'maxwell'@'localhost';
[maxwell@elite ~]$ 

Not the answer you're looking for? Browse other questions tagged or ask your own question.