Коротка відповідь: використовувати"$@"
(зверніть увагу на подвійні лапки). Інші форми дуже рідко корисні.
"$@"
- досить дивний синтаксис. Його замінюють усі позиційні параметри, як окремі поля. Якщо немає позиційних параметрів ( $#
є 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`