В чем разница между "$ @" и "$ *" в Bash?

Мне кажется, что они оба сохраняют все аргументы командной строки.

Так есть ли разница между двумя?

Ответ 1

Разница тонкая; "$*" создает один аргумент, разделенный переменной $IFS, а "[email protected]" будет расширяться на отдельные аргументы. В качестве примера рассмотрим:

for i in "[email protected]"; do echo "@ '$i'"; done
for i in "$*"; do echo "* '$i'"; done

При запуске с несколькими аргументами:

./testvar foo bar baz 'long arg'
@ 'foo'
@ 'bar'
@ 'baz'
@ 'long arg'
* 'foo bar baz long arg'

Подробнее:

http://www.gnu.org/software/bash/manual/bashref.html#Special-Parameters

$*

Расширяется до позиционных параметров, начиная с одного. Когда расширение происходит в двойных кавычках, оно расширяется до одного слова со значением каждого параметра, разделенным первым символом специальной переменной IFS. То есть "$ *" эквивалентно "$ 1c $2c...", где c - первый символ значения переменной IFS. Если IFS не задано, параметры разделяются пробелами. Если IFS равно null, параметры объединяются без промежуточных разделителей.

[email protected]

Расширяется до позиционных параметров, начиная с одного. Когда расширение происходит в двойных кавычках, каждый параметр расширяется до отдельного слова. То есть "$ @" эквивалентно "$ 1" "$ 2".... Если двойное кавычное разложение происходит внутри слова, разложение первого параметра соединяется с начальной частью исходного слова, а расширение последнего параметра соединяется с последней частью исходного слова. Когда нет позиционных параметров, "$ @" и [email protected]расширяются до нуля (т.е. Удаляются).

Ответ 2

Ключевым отличием от моего POV является то, что "[email protected]" сохраняет исходный номер аргументов. Это единственная форма, которая делает.

Например, если файл my_script содержит:

#!/bin/bash

main()
{
   echo 'MAIN sees ' $# ' args'
}

main $*
main [email protected]

main "$*"
main "[email protected]"

### end ###

и я запускаю его следующим образом:

my_script 'a b c' d e

Я получу этот вывод:

MAIN sees  5  args
MAIN sees  5  args
MAIN sees  1  args
MAIN sees  3  args