Najmuddin
Najmuddin

Reputation: 155

bash adds escape chars when passing a string with quotes

I'm trying to run a msyql command which includes a quoted string, for eg:

mysql -h host -u=user -p=pass -e "show tables" database.

Here I'm having difficulty to pass "show tables" with quotes to a fuction that executes the command.

run_cmd()  # Run a command
{
  local output=$1
  local timeout=$2
  shift 2
  ( $* > $output 2>&1 ) &
# ....
}

# Query mysql 

query_mysql(){
    local mysql_cmd=( "mysql -h $host --user=$user --password=$pass -e "show tables" $db")
    run_cmd $output $timeout "${mysql_cmd[@]}"
}
query_mysql

I tried many combinations, however the command get executed either without quotes or with multiple single/double/escape chars. In all cases the final command becomes invalid due to missing/additional quotes/chars.

few of my attempts & the final command:

"show tables"
mysql -h localhost --user=root --password=foo -e show tables db1 

'show tables'
mysql -h localhost --user=root --password=foo -e ''\''show' 'tables'\''' db1

\"show tables\"
mysql -h localhost --user=root --password=foo -e '"show' 'tables"' db1

Any suggestions to pass the quoted string as is?

Thanks in advance!

Upvotes: 1

Views: 155

Answers (1)

Etan Reisner
Etan Reisner

Reputation: 80921

Don't quote unrelated words inside the array assignment. So use

local mysql_cmd=( mysql -h "$host" --user="$user" --password="$pass" -e "show tables" "$db")

instead of

local mysql_cmd=( "mysql -h $host --user=$user --password=$pass -e "show tables" $db")

See the difference between yours

$ mysql_cmd=( "mysql -h $host --user=$user --password=$pass -e "show tables" $db")
$ printf %q\\n "${mysql_cmd[@]}"
mysql\ -h\ host\ --user=user\ --password=pass\ -e\ show
tables\ db

and mine

$ mysql_cmd=( mysql -h "$host" --user="$user" --password="$pass" -e "show tables" "$db")
$ printf %q\\n "${mysql_cmd[@]}"
mysql
-h
host
--user=user
--password=pass
-e
show\ tables
db

Also don't use unquoted $* when you execute the command. You probably want to use "$@" instead. So

( "$@" > $output 2>&1 ) &

which doesn't actually need the sub-shell () and can probably just be

"$@" > $output 2>&1 &

See http://mywiki.wooledge.org/BashFAQ/050 for more details about why this array command usage needs to work this way (and why you were having such trouble with your attempts).

Upvotes: 3

Related Questions