The Idiosyncrasies of Bash's quotes
The Bash shell has many quirks and takes a lot of time to master. The Fish shell has a cleaner syntax but is not installed on many systems. The quote idiosyncrasy of Bash is presented.
I have used Bash a my default shell for several years and written a fair amount of script with it. There is a good list of pitfalls that has helped me steer clear of the great number of mistakes that can break your scripts.
After I switched my shell to Fish, I started to get
the impression that I spend too much time thinking about those Bash pitfalls
instead of writing scripts. I wanted to write a simple script that I would call
ca
that would call git commit -a -m '...'
for me where the ...
would be
all the arguments to ca
. So I would enter this:
ca One two three
And get this:
git commit -a -m 'One two three'
I tried to do this in Fish and was looking for something like $*
or $@
and
could not find something. What I found was $argv
which is an array with all
the arguments. So my script was just:
git commit -a -m "$argv"
Since that took me minutes to figure out something that was so easy and a little convoluted in Bash, I was reminded of Linus Torwalds who said "CVS hasn't rotten my brain" about the design principles of git in a talk (9:02). So I do think that Bash has convoluted my mind and I am trying to get rid of that.
If you compare Bash to Fish or even Python, it is painful.
Command line arguments
Do you know the difference between $*
, $@
, "$*
and "$@"
? All them
contain all command line arguments. But how do they with spaces in the
arguments exactly? And how many words will each be?
Take a look at this program and try to say what the output would be.
arg-echo() { local index=1 for arg do echo $index "$arg" (( index++ )) done echo } arg-test() { echo '$*' arg-echo $* echo '$@' arg-echo $@ echo '"$*"' arg-echo "$*" echo '"$@"' arg-echo "$@" } arg-test one two "string with space"
The output is the following with Bash 4.3.11(1):
$* 1 one 2 two 3 string 4 with 5 space $@ 1 one 2 two 3 string 4 with 5 space "$*" 1 one two string with space "$@" 1 one 2 two 3 string with space
Would you have known that? And a friend put it concisely, I could not say it better:
"The sole fact that I am supposed to know this is a fault in the design."
In Bash, the right thing for my git script would be git commit -am "$*"
. In
Fish, there is only $argv
and "$argv"
. The first gives the arguments and
does not split spaces again, the latter makes it one big string. They relate to
"$@"
and "$*"
in Bash.