I often find that I've concocted some incantation which I'd like to reuse, but it's far too susceptible to ad-hoc tweaking to store as a function. These commands often have some critical variable component, such as a filename, buried deep within. I'd like to move that component to the end of the command.
For example, my latest witchcraft prints the table definitions of all new INSERT
statements in a diff file:
for T in $(grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" foo.diff | sort -u) ; do docker-compose exec mysql mysqldump --no-data some_database $T | grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT" | sed "s/ COMMENT .*,$/,/" | sed "s/CONSTRAINT \`\w*\` //" | sed "s/^) ENGINE.*;/);/" ; done
Formatted for legibility:
for T in $(grep -oP "(?<=^\+INSERT INTO \`)[\w-]+(?=\`)" foo.diff | sort -u)
do
docker-compose exec mysql mysqldump --no-data some_database $T
| grep -P "^\s*\`|^CREATE|^\) |^\s*CONSTRAINT"
| sed "s/ COMMENT .*,$/,/"
| sed "s/CONSTRAINT \`\w*\` //"
| sed "s/^) ENGINE.*;/);/"
done
I'm very likely going to want to use this again in the future on a file that is not called foo.diff
, so I'd like the command to end with the file name. My first inclination would be to just wrap the whole thing in a function, and have the filename be the $1 parameter.
However, it is very likely that I'm going to tweak it further as I run it. Add a bit of sed here, maybe a touch of awk there. So I'd still like the whole command to be on the CLI when I Ctrl-P
to run it again. Therefore I decided to use a variable:
$ FILENAME=diff-03-04.sql
That's appropriate for this specific example as I'll be using the same file for each incantation today, but there exist other examples where I'd really like to be able to just tweak the end of the command. So this:
$ for Q in $(foo Torvalds bar) ; do baz $Q ; done
Would become something akin to (but not necessarily exactly):
$ for Q in $(foo SOME_MAGIC_HERE bar) ; do baz $Q ; done < Torvalds
type f
for function f to see its definition. Copy and paste to suitcmd | while read
loops rather thanfor in $(cmd)
loops.$1
parameter" –sh -c '…' sh foo.diff
. This however introduces an additional level of quoting.myfunc() { echo "$1"; }; myfunc foo.diff