问题
The following command is throwing an unterminated substitute pattern error in bash:
eval $(echo "sed '" "s,@\("{a..u}{a..z}"\),\n\n\1,;" "'")
But not for everyone. Linux apparently works fine. Mac throws the unterminated substitute pattern error.
How can I reorganize to make this work?
Here's the entire bash command (the goal is to cleanly output current MySQL settings into my.cnf) :
{
# Print version, user, host and time
echo -e "# MYSQL VARIABLES {{{1\n##\n# MYSQL `
mysql -V | sed 's,^.*\(V.*\)\, for.*,\1,'
` - By: `logname`@`hostname -f` on `date +%c`\n##"
for l in {a..z}; do
# Get mysql global variables starting with $l
echo '#'; mysql -NBe "SHOW GLOBAL VARIABLES LIKE '${l}%'" |
# Transorm it
sed 's,\t,^= ,' |
column -ts^ |
tr "\n" '@' |
eval $(echo "sed '" "s,@\("{a..u}{a..z}"\),\n\n\1,;" "'") |
eval $(echo "sed '" "s,@\(innodb_"{a..z}{a..z}"\),\n\n\1,;" "'") |
tr '@' "\n" |
sed 's,^,# ,g'
done
echo -e "#\n##\n# MYSQL VARIABLES }}}1";
} | tee ~/mysql-variables.log
回答1:
The default sed in OS X is an BSD version of sed. Just tested:
- the above fails in OS X's default sed,
- and works with the GNU version (gsed - installed from macports).
So, probably the BSD version doesn't handles such long substitution command series.
You can try use the next:
eval $(echo "perl -ple '" "s,@("{a..u}{a..z}"),\n\n\1,;" "'")
And maybe I didn't understand right your goal, but what is a wrong with a much simpler?
sed 's/@\([a-u][a-z]\)/\n\n\1/' #or
sed 's/@\("[a-u][a-z]"\)/\n\n\1/'
EDIT
Once again i'm only focused to the 1st code-line and not the whole solution. So created a bash/perl version what works without problems on OS X (with default OS X tools).
The next code
MYSQLCMD=/usr/local/mysql-5.6.16-osx10.7-x86_64/bin/mysql #your path to mysql command
printf "# MYSQL VARIABLES {{{1\n##\n# MYSQL %s " "$($MYSQLCMD -V | sed 's/.*\(Ver .*\),.*/\1/')"
printf " - By: %s@%s on %s\n" $(logname) $(hostname -f) "$(date +%c)"
perl -e "\$s=qx($MYSQLCMD -NBe 'SHOW GLOBAL VARIABLES');" \
-e 'for("aa".."uz"){$s=~s/^($_)/#\n$1/m;$s=~s/^(innodb_$_)/#\n$1/m};' \
-e '$s=~s/(.*)\t(.*)/sprintf "# %-55s= %s",$1,$2/gem;print $s'
printf "#\n##\n# MYSQL VARIABLES }}}1\n";
roughly do the same what the original code.
回答2:
Try breaking the command up into multiple commands:
eval "$(printf "sed "; echo "-e 's,@\("{a..z}{a..z}"\),\n\n\1,'")"
But note that sed on OSX also probably doesn't like \n as a newline, so you'll have to do:
$ nl='
'
$ eval "$(printf "sed "; echo "-e 's,@\("{a..z}{a..z}"\),\\$nl\\$nl\1,'")"
I would strongly recommend finding a better solution. Probably via perl.
回答3:
For a quick fix, try (see below for a preferable alternative that doesn't use eval):
eval "$(echo "sed '" "s,@\("{a..u}{a..z}"\),"$'\\\n\\\n'"\1,"$'\n' "'")"
As @jm666 hints at, FreeBSD sed (at least the version that comes with OS X 10.9.4) has a limit on the size of individual lines in a script (command string) - 4096 bytes - and the large single-line string that results from your use of bash's brace (range) expansion ({a..u}{a..z}) exceeds that limit.
The above works around that by putting each s call on its own line by appending $'\n' (which in bash expands to an actual newline - see below) rather than ; to the string to be brace-expanded.
Also note that \n\n was replaced with spliced-in $'\\\n\\\n', because FreeBSD sed doesn't support \n escapes in replacement strings (treats them as literal n chars). $'\\\n\\\n' inserts actual newlines - escaped with \ - using a bash feature called ANSI C-quoting.
(Similarly, FreeBSD sed also doesn't support escape sequence \t in regexes to represent chars, so your sed 's,\t,^= ,' command must be replaced with sed 's,'$'\t'',^= ,'.)
Note that the entire string passed to eval must then be double-quoted so as to ensure that the newlines are passed through to sed.
Note that you could in theory still hit a limit: the max. length of a command line, but that limit is much higher: a little less than 256 KB on OS X.
Also, you may pass long sed scripts via a file, by using the -f option.
Generally, it's better to avoid use of eval, so here's an alternative:
sed "$(printf %s "s,@\("{a..u}{a..z}"\),"$'\\\n\\\n'"\1,"$'\n')"
来源:https://stackoverflow.com/questions/24853398/how-can-i-reorganize-nested-quotes-within-sed-regex-in-a-bash-script-that-trigge