Any ./shift subcommand that forwards arguments mangles them, because $@ is passed unquoted at every level of the call chain. The most visible casualty is ./shift mysql -e "<sql>", which never runs the SQL and instead prints mysql's usage text.
Reproducing
$ ./shift mysql -e "SHOW VARIABLES LIKE 'character_set%';"
Expected: the variables. Actual: mysql's help/usage output.
Cause
The SQL string is split on whitespace before mysql ever sees it. shift is a bash script (#!/usr/bin/env bash), and unquoted $@ in bash re-splits each positional parameter on IFS and then glob-expands the results. The relevant chain, all unquoted:
# dispatcher, bottom of the file
sub_${SUB_CMD} $@
sub_mysql() { # - Open a mysql prompt with the db selected
cd "${ROOT}"
sub_compose exec db mysql -u ${MYSQL_USER} -h db -P 3306 -p"${MYSQL_PASSWORD}" ${MYSQL_DATABASE} $@
}
sub_compose() { # <cmd...> - Run a compose with associated files
docker compose $@
}
So -e "SHOW VARIABLES LIKE 'character_set%';" arrives at mysql as five separate arguments:
[-e] [SHOW] [VARIABLES] [LIKE] ['x%';]
mysql receives -e SHOW, then treats VARIABLES, LIKE, and the rest as stray arguments, and bails out to its usage text.
Glob expansion makes it worse. Because the split words are also subject to pathname expansion, an asterisk in the SQL expands against the current directory:
$ ./shift mysql -e "SELECT * FROM calevent LIMIT 1"
delivers this to mysql:
[-e] [SELECT] [app] [backend] [bin] [cal] [CLAUDE.md] [db-local-empty.sql]
[docker-compose.yml] [docs] [LICENSE.md] [netlify.toml] ... [services]
Note that quoting $@ in sub_mysql alone is not sufficient, since the arguments are re-split again inside sub_compose, and once more by the dispatcher.
Affected subcommands
Every one that forwards $@: mysql, mysql-pipe, mysqldump, compose, attach, logs, and the dispatcher itself. mysql-pipe happens to work in practice only because SQL reaches it on stdin rather than as an argument.
Workaround
Pipe the SQL instead of passing it as an argument:
printf "SHOW VARIABLES LIKE 'character_set%%';\n" | ./shift mysql-pipe
Suggested fix
Quote "$@" at each level (dispatcher, sub_compose, and each sub_* that forwards arguments). Worth a pass over the other unquoted expansions in the same lines while in there.
This is easy to trip over and hard to diagnose, since mysql's usage output does not look like a quoting error. It also bit the verification steps written into #1077.
Any
./shiftsubcommand that forwards arguments mangles them, because$@is passed unquoted at every level of the call chain. The most visible casualty is./shift mysql -e "<sql>", which never runs the SQL and instead prints mysql's usage text.Reproducing
Expected: the variables. Actual: mysql's help/usage output.
Cause
The SQL string is split on whitespace before mysql ever sees it.
shiftis a bash script (#!/usr/bin/env bash), and unquoted$@in bash re-splits each positional parameter onIFSand then glob-expands the results. The relevant chain, all unquoted:So
-e "SHOW VARIABLES LIKE 'character_set%';"arrives at mysql as five separate arguments:mysql receives
-e SHOW, then treatsVARIABLES,LIKE, and the rest as stray arguments, and bails out to its usage text.Glob expansion makes it worse. Because the split words are also subject to pathname expansion, an asterisk in the SQL expands against the current directory:
delivers this to mysql:
Note that quoting
$@insub_mysqlalone is not sufficient, since the arguments are re-split again insidesub_compose, and once more by the dispatcher.Affected subcommands
Every one that forwards
$@:mysql,mysql-pipe,mysqldump,compose,attach,logs, and the dispatcher itself.mysql-pipehappens to work in practice only because SQL reaches it on stdin rather than as an argument.Workaround
Pipe the SQL instead of passing it as an argument:
Suggested fix
Quote
"$@"at each level (dispatcher,sub_compose, and eachsub_*that forwards arguments). Worth a pass over the other unquoted expansions in the same lines while in there.This is easy to trip over and hard to diagnose, since mysql's usage output does not look like a quoting error. It also bit the verification steps written into #1077.