Коротка відповідь: використовувати"$@" (зверніть увагу на подвійні лапки). Інші форми дуже рідко корисні.
"$@"- досить дивний синтаксис. Його замінюють усі позиційні параметри, як окремі поля. Якщо немає позиційних параметрів ( $#є 0), то "$@"розширюється до нічого (не порожній рядок, а список з 0 елементами), якщо є один позиційний параметр, то "$@"він еквівалентний "$1", якщо є два позиційні параметри, то "$@"еквівалентно "$1" "$2"тощо.
"$@"дозволяє передавати аргументи сценарію або функції іншій команді. Це дуже корисно для обгортків, які роблять такі речі, як встановлення змінних середовища, підготовка файлів даних тощо перед тим, як викликати команду з тими ж аргументами та параметрами, з якими викликалася обгортка.
Наприклад, наступна функція фільтрує вихід cvs -nq update. Окрім фільтрування виходу та статусу повернення (що є, grepа не статусом cvs), виклик cvssmдеяких аргументів поводиться як дзвінок cvs -nq updateіз цими аргументами.
cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }
"$@"розширюється до списку позиційних параметрів. У оболонках, які підтримують масиви, існує аналогічний синтаксис, який можна розгорнути до списку елементів масиву: "${array[@]}"(дужки є обов'язковими, крім zsh). Знову ж таки, подвійні лапки дещо вводять в оману: вони захищають від розщеплення поля та генерації шаблону елементів масиву, але кожен елемент масиву опиняється у власному полі.
Деякі древні оболонки мали те, що, ймовірно, помилка: коли не було позиційних аргументів, "$@"розширювались на одне поле, що містить порожню рядок, а не в поле. Це призвело до вирішення${1+"$@"} (стало відомим за допомогою документації Perl ). Зачіпаються лише старіші версії фактичної оболонки Bourne та реалізації OSF1, жодна з її сучасних сумісних замін (ash, ksh, bash,…) не є. /bin/shце не впливає на будь-яку систему, що була випущена в 21 столітті, про яку я знаю (якщо ви не рахуєте версію технічного обслуговування Tru64, і навіть там /usr/xpg4/bin/shє безпечний, тому #!/bin/shвпливають лише сценарії, а не #!/usr/bin/env shсценарії, якщо ваш PATH налаштований на відповідність POSIX) . Коротше кажучи, це історичний анекдот, про який вам не потрібно хвилюватися.
"$*"завжди розширюється на одне слово. Це слово містить позиційні параметри, з'єднані між собою пробілом. (Більш загально, роздільник є першим символом значення IFSзмінної. Якщо значення IFSпорожнього рядка, то роздільник - порожній рядок.) Якщо позиційних параметрів немає, то "$*"це порожня рядок, якщо є дві позиційних параметрів і IFSмає його значення за замовчуванням, то "$*"еквівалентно "$1 $2"тощо.
$@а $*зовнішні котирування рівноцінні. Вони розширюються до списку позиційних параметрів, як окремі поля, як-от "$@"; але кожне результуюче поле потім розділяється на окремі поля, які трактуються як шаблони підстановки імен файлів, як зазвичай, із розширеннями змінних змін без змін.
Наприклад, якщо поточний каталог містить три файли bar, bazі foo, потім:
set -- # no positional parameters
for x in "$@"; do echo "$x"; done # prints nothing
for x in "$*"; do echo "$x"; done # prints 1 empty line
for x in $*; do echo "$x"; done # prints nothing
set -- "b* c*" "qux"
echo "$@" # prints `b* c* qux`
echo "$*" # prints `b* c* qux`
echo $* # prints `bar baz c* qux`
for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`