"Передача всех аргументов в Bash-скрипте"
Я пишу очень простой скрипт, который вызывает другой скрипт, и мне нужно передать параметры из моего текущего скрипта в исполняемый скрипт.
Например, имя моего скрипта — foo.sh
, и он вызывает bar.sh
.
Содержимое foo.sh
:
bar $1 $2 $3 $4
Как мне сделать это, не указывая явно каждый параметр?
5 ответ(ов)
В данном случае я рекомендую использовать "$@"
вместо простого $@
, если вы хотите, чтобы ваши параметры передавались так же, как были получены.
Обратите внимание на следующий пример:
Скрипт no_quotes.sh
#!/bin/bash
echo_args.sh $@
Скрипт quotes.sh
#!/bin/bash
echo_args.sh "$@"
Скрипт echo_args.sh
#!/bin/bash
echo Received: $1
echo Received: $2
echo Received: $3
echo Received: $4
Теперь давайте посмотрим, что произойдет при запуске этих скриптов:
Запуск
./no_quotes.sh first second
:Received: first Received: second Received: Received:
Запуск
./no_quotes.sh "one quoted arg"
:Received: one Received: quoted Received: arg Received:
Запуск
./quotes.sh first second
:Received: first Received: second Received: Received:
Запуск
./quotes.sh "one quoted arg"
:Received: one quoted arg Received: Received: Received:
Как видно из результатов, когда мы передаем параметры без кавычек ($@
), Bash разбивает аргументы на отдельные слова, если они содержат пробелы. В случае с "$@"
все аргументы передаются как есть, что позволяет сохранить их целостность. Поэтому использование "$@"
— это лучший подход, когда вы работаете с аргументами, содержащими пробелы или другие специальные символы.
В bash и других оболочках, подобных Bourne:
bar "$@"
Команда "$@"
используется для передачи всех аргументов скрипта или функции bar
. Она экранирует аргументы так, чтобы они корректно обрабатывались даже если они содержат пробелы или специальные символы. То есть, "$@"
передает каждый аргумент как отдельный параметр, что отличается от $*
, который объединяет все аргументы в одну строку. Это гарантирует, что каждый аргумент будет правильно интерпретирован в функции или команде bar
.
В этом ответе мы рассмотрим различия между "$@"
, $@
, "*"
, и *
в bash, особенно в контексте передачи аргументов в скрипты.
Текст скрипта test.sh
:
#!/usr/bin/env bash
echo "================================="
echo "Quoted DOLLAR-AT"
for ARG in "$@"; do
echo $ARG
done
echo "================================="
echo "NOT Quoted DOLLAR-AT"
for ARG in $@; do
echo $ARG
done
echo "================================="
echo "Quoted DOLLAR-STAR"
for ARG in "$*"; do
echo $ARG
done
echo "================================="
echo "NOT Quoted DOLLAR-STAR"
for ARG in $*; do
echo $ARG
done
echo "================================="
Теперь давайте запустим этот скрипт с различными аргументами:
./test.sh "arg with space one" "arg2" arg3
Результат выполнения будет следующим:
=================================
Quoted DOLLAR-AT
arg with space one
arg2
arg3
=================================
NOT Quoted DOLLAR-AT
arg
with
space
one
arg2
arg3
=================================
Quoted DOLLAR-STAR
arg with space one arg2 arg3
=================================
NOT Quoted DOLLAR-STAR
arg
with
space
one
arg2
arg3
=================================
Объяснение:
"$@"
:- Аргументы автоматически обрабатываются как отдельные элементы (каждый аргумент остается целым, включая пробелы внутри). Это значит, что если вы передали аргумент с пробелами, он будет распечатан на новой строке в цикле.
$@
(без кавычек):- В этом случае bash разбивает все аргументы на отдельные слова. Если переданный аргумент содержит пробелы, они будут считаться разделителями, и каждый "слово" будет распечатано отдельно.
"$*"
:- Соединяет все аргументы в одну строку, разделённую первым символом IFS (обычно пробел). Таким образом, вывод для этого случая будет одной строкой, содержащей все аргументы, включая пробелы внутри.
$*
(без кавычек):- Работает аналогично
"$*"
, разбивая аргументы на слова и игнорируя пробелы, при этом каждый элемент будет распечатан отдельно.
- Работает аналогично
Резюме:
- Использование
"$@"
предпочтительнее, когда вам нужно сохранить аргументы, содержащие пробелы, как отдельные единицы. - В случае
"$*"
все аргументы будут объединены в одну строку. Выбор использования того или иного механизма зависит от того, как вы хотите обрабатывать аргументы в вашем скрипте.
Этот сценарий на Bash позволяет вам видеть, как аргументы передаются в ваш скрипт. Вот перевод вашего сообщения в стиле ответа на StackOverflow:
#!/usr/bin/env bash
while [ "$1" != "" ]; do
echo "Получено: ${1}" && shift;
done;
Этот скрипт будет выводить каждый аргумент, переданный ему при запуске, в виде строки "Получено: <аргумент>". Цикл while
продолжается до тех пор, пока не будут обработаны все аргументы. Команда shift
сдвигает позиционные параметры влево, демонтируя текущий аргумент ($1
) и позволяя следующему аргументу занять его место.
Это полезный прием для тестирования и отладки, позволяющий вам убедиться, что ваши аргументы корректно передаются в скрипт.
Когда вы включаете $@
в строку, заключённую в кавычки, вместе с другими символами, поведение может быть неожиданным, особенно когда имеется несколько аргументов. В таких случаях только первый аргумент будет включен в кавычки.
Например, рассмотрим следующий скрипт:
#!/bin/bash
set -x
bash -c "true foo $@"
Если вы запустите этот скрипт с аргументами, например:
$ bash test.sh bar baz
Вы получите следующий вывод:
+ bash -c 'true foo bar' baz
Как видно, только первый аргумент (bar
) попадает в кавычки, а остальные (baz
) выходят за пределы.
Теперь, если сначала присвоить $@
другой переменной, например:
#!/bin/bash
set -x
args="$@"
bash -c "true foo $args"
При запуске с теми же аргументами:
$ bash test.sh bar baz
Вы получите:
+ args='bar baz'
+ bash -c 'true foo bar baz'
В этом случае все аргументы успешно передаются в команду, так как мы сначала записали их в переменную args
, и при подстановке в строку кавычки больше не влияют на разделение аргументов.
Таким образом, рекомендуется использовать переменные для хранения аргументов, если вы хотите избежать неожиданных результатов при использовании $@
в кавычках.
Проверьте количество аргументов, переданных Bash-скрипту
Ошибка "Слишком длинный список аргументов" для команд rm, cp, mv
Извлечение имени файла и расширения в Bash
Как работает "cat << EOF" в bash?
Передача параметров в функцию Bash