Escape a star (*) character in bash

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;

Solution 1:

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

Solution 2:

  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.