1

I have a script named cpodin that copies several build artifacts to another directory. Afterward, I edit SHA1SUM in the destination directory.

For example:

cpodin /foo/bar/baz
vim !$/SHA1SUM

How do I make the latter command an alias named fixsha that takes no argument and edits SHA1SUM in the directory named by the previous command’s last argument? An alias of

alias fixsha='vim !$/SHA1SUM'

results in attempts to edit !$/SHA1SUM instead of /foo/bar/baz/SHA1SUM.

1 Answer 1

2

Bash does not perform history expansion after alias expansion, so you have to do so explicitly using history, documented in Bash History Builtins and excerpted below.

history -ps args

  • -p
    Perform history substitution on the args and display the result on the standard output, without storing the results in the history list.
  • -s
    The args are added to the end of the history list as a single entry.

An alias of alias fixsha='vim $(history -p !$)/SHA1SUM' will work most of the time but not as intended when !$ expands to a path that contains whitespace. Adding double-quotes around the path argument will protect any escapes on whitespace and results in vim "/foo/bar\ baz/SHA1SUM" rather than the desired vim /foo/bar\ baz/SHA1SUM or its equivalent vim "/foo/bar baz/SHA1SUM".

So in addition to explicit history expansion, eval is also necessary to unwrap one layer of quoting.

alias fixsha='eval vim "$(history -p !$)/SHA1SUM"'

Note: You may be surprised to learn that the double-quotes in the above alias definition are unnecessary. This is because no whitespace is between the expanded value of !$ and /SHA1SUM to trigger bash’s word splitting. However, I like them being there to emphasize the intent that it is expanding to a single argument.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .