Краткий ответ: используйте"$@"
(обратите внимание на двойные кавычки). Другие формы очень редко полезны.
"$@"
довольно странный синтаксис. Он заменяется всеми позиционными параметрами, как отдельные поля. Если позиционных параметров нет ( $#
равен 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`