1

Throughout the day, I type something like this frequently:

git stash push -u -m "some phrase as a message"

I would prefer to type instead:

stpu some phrase as a message

So with help from this answer, I created a function in my ~./bashrc:

function stpu() {
  git stash push -u -m "`date +'%Y-%m-%d %H:%M:%S'` ${@}"
}

Now I'm able to type stpu "some phrase as a message", which is pretty close to what I want.

How can I adjust my function such that I can omit the double-quotes?

I've tried many different variations (adding more double-quotes that are escaped, adding single-quotes, etc) but haven't gotten it to work.

Ryan
  • 22,332
  • 31
  • 176
  • 357
  • 3
    You need to use `"$*"` instead of `"$@"` if you want all your arguments joined together in a string. That said, I strongly advise against doing so; it'll have unwanted side effects. – Charles Duffy Nov 13 '20 at 15:42
  • 1
    BTW, re: function syntax, see https://wiki.bash-hackers.org/scripting/obsolete -- it's better to just use `stpu() {` with no preceding `function`. – Charles Duffy Nov 13 '20 at 15:47
  • 1
    BTW, the arguments about security and correctness made in my answer are also why it's better to run `ssh somehost 'command to run'` than `ssh somehost command to run`. If you don't quote your arguments to `ssh`, what it does with those that are meant for the remote system is identical to the behavior of `"$*"` -- munging them together into a single string, but only after the invoking shell has had its way with them first. – Charles Duffy Nov 13 '20 at 15:51
  • Note that the quotes are just for escaping individual characters in bulk; they don't define a string (as everything in shell is *already* a string). `"foo bar"` is equivalent to `\f\o\o\ \b\a\r`, with every character in quotes being treated as if it were back-slash escaped. Since most of those characters don't have a special meaning to the shell (`\f` is just `f`, etc), it's also equivalent to `foo\ bar`, since only the space would be used by the shell to parse the sequence as two words, rather than a single word that contains a space. – chepner Nov 13 '20 at 16:14

1 Answers1

10

You can sometimes omit the quotes if you use "$*" instead of "$@"

This will concatenate all your arguments together into a single string, separated with spaces (by default; the first character in IFS, if it's been overridden). -m expects a single string to follow it (instead of a separate argument per word), so this is exactly what it wants.


This is not reliable, and it's better to just use the quotes.

Security

Consider as an example if you want to use the commit message: Make $(rm -rf ~) safe in an argument name for a security fix. If this string is unquoted (or double quoted), the command is executed before your function is ever started (which makes sense: a function can't be called until after its argument list is known), so there's nothing your function can do to fix it. In this context, using single quotes to prevent the command substitution from taking place is the correct and safe practice.

(To single-quote a string that contains single quotes, consider using ANSI C-like strings: $'I\'m a single-quoted string that contains a single quote')

Correctness

Or, as another example: Process only files matching *.csv -- if it's not quoted, the *.csv can be replaced with a list of CSV files that exist in the directory where you ran the command. Again, this happens before your function is ever started, so nothing inside the function can prevent it.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Wow, good points. I'm glad I asked. I'll accept the answer when I'm allowed to. Thanks. – Ryan Nov 13 '20 at 15:51