When they are not quoted, $*
and $@
are the same. You shouldn't use either of these, because they can break unexpectedly as soon as you have arguments containing spaces or wildcards.
"$*"
expands to a single word "$1c$2c..."
. Usually c
is a space, but it's actually the first character of IFS
, so it can be anything you choose.
The only good use I've ever found for it is:
join arguments with comma (simple version)
join1() {
typeset IFS=,
echo "$*"
}
join1 a b c # => a,b,c
join arguments with the specified delimiter (better version)
join2() {
typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
shift
echo "$*"
}
join2 + a b c # => a+b+c
"$@"
expands to separate words: "$1"
"$2"
...
This is almost always what you want. It expands each positional parameter to a separate word, which makes it perfect for taking command line or function arguments in and then passing them on to another command or function. And because it expands using double quotes, it means things don't break if, say, "$1"
contains a space or an asterisk (*
).
Let's write a script called svim
that runs vim
with sudo
. We'll do three versions to illustrate the difference.
svim1
#!/bin/sh
sudo vim $*
svim2
#!/bin/sh
sudo vim "$*"
svim3
#!/bin/sh
sudo vim "$@"
All of them will be fine for simple cases, e.g. a single file name that doesn't contain spaces:
svim1 foo.txt # == sudo vim foo.txt
svim2 foo.txt # == sudo vim "foo.txt"
svim2 foo.txt # == sudo vim "foo.txt"
But only $*
and "$@"
work properly if you have multiple arguments.
svim1 foo.txt bar.txt # == sudo vim foo.txt bar.txt
svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"
And only "$*"
and "$@"
work properly if you have arguments containing spaces.
svim1 "shopping list.txt" # == sudo vim shopping list.txt # two file names!
svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
svim3 "shopping list.txt" # == sudo vim "shopping list.txt"
So only "$@"
will work properly all the time.
typeset
is how to make a local variable in ksh
(bash
and ash
use local
instead). It means IFS
will be restored to its previous value when the function returns. This is important, because the commands you run afterward might not work properly if IFS
is set to something non-standard.
Best Answer
If you take a look at the ANSI ASCII standard, the lower part of the character set (the first 32) are reserved "control characters" (sometimes referred to as "escape sequences"). These are things like the NUL character, Life Feed, Carriage Return, Tab, Bell, etc. The vast majority can be emulated by pressing the Ctrl key in combination with another key.
The 27th (decimal) or
\033
octal sequence, or0x1b
hex sequence is the Escape sequence. They are all representations of the same control sequence. Different shells, languages and tools refer to this sequence in different ways. Its Ctrl sequence is Ctrl-[, hence sometimes being represented as^[
,^
being a short hand for Ctrl.You can enter control character sequences as a raw sequences on your command line by proceeding them with Ctrl-v. Ctrl-v to most shells and programs stops the interpretation of the following key sequence and instead inserts in its raw form. If you do this with either the Escape key or Ctrl-v it will display on most shells as
^[
. However although this sequence will get interpreted, it will not cut and paste easily, and may get reduced to a non control character sequence when encountered by certain protocols or programs.To get around this to make it easier to use, certain utilities represent the "raw" sequence either with
\033
(by octal reference), hex reference\x1b
or by special character reference\e
. This is much the same in the way that\t
is interpreted as a Tab - which by the way can also be input via Ctrl-i, or\n
as newline or the Enter key, which can also be input via Ctrl-m.So when Gilles says:
He is saying decimal ASCII 27, octal 33, hex 1b, Ctrl-[ and
\e
are all equal he means they all refer to the same thing (semantically).When Demizey says
He means semantically, but if you press Ctrl-v Ctrl-[ this is exactly the same as
\e
, the raw inserted sequence will most likely be treated the same way, but this is not always guaranteed, and so it recommended to use the programmatically more portable\e
or0x1b
or\033
depending on the language/shell/utility being used.