Как итерировать аргументы в Bash-скрипте
Я столкнулся с проблемой при написании сложной команды, которую хотел бы преобразовать в shell/bash скрипт. Я могу легко записать её с использованием $1
:
foo $1 args -o $1.ext
Однако я хочу иметь возможность передавать несколько имен файлов на вход скрипту. Как правильно это сделать?
Кроме того, мне нужно обработать имена файлов, содержащие пробелы.
5 ответ(ов)
Используйте "$@"
для представления всех аргументов:
for var in "$@"
do
echo "$var"
done
Этот код будет перебирать каждый аргумент и выводить его на отдельной строке. $@
ведет себя похоже на $*
, за исключением того, что, когда он заключен в кавычки, аргументы правильно разделяются, даже если они содержат пробелы:
sh test.sh 1 2 '3 4'
1
2
3 4
Обратите внимание, что ответ Роберта правильный и работает также в sh
. Вы можете (портативно) упростить его еще больше:
for i in "$@"
эквивалентно:
for i
Т.е. вам не нужно ничего дополнительно!
Вот пример тестирования ($
обозначает командную строку):
$ set a b "spaces here" d
$ for i; do echo "$i"; done
a
b
spaces here
d
$ for i in "$@"; do echo "$i"; done
a
b
spaces here
d
Впервые я прочитал об этом в книге Unix Programming Environment авторов Кернигана и Пайка.
В bash
это подтверждается в документации по команде help for
:
for NAME [in WORDS ... ;] do COMMANDS; done
Если
'in WORDS ...;'
отсутствует, то предполагается, что используется'in "$@"'
.
Для простых случаев вы также можете использовать команду shift
. Она обрабатывает список аргументов как очередь. Каждый вызов shift
удаляет первый аргумент, а индексы оставшихся аргументов уменьшаются на единицу.
Вот пример, который выводит все переданные аргументы:
# Этот код печатает все аргументы
while test $# -gt 0
do
echo "$1"
shift
done
В этом примере цикл продолжается до тех пор, пока количество аргументов больше нуля ($#
), и каждый раз первый аргумент выводится на экран, после чего он удаляется из списка аргументов с помощью shift
.
Вы также можете получить доступ к элементам массива, например, если не хотите перебирать все элементы с помощью цикла. Вот пример:
argc=$#
argv=("$@")
for (( j=0; j<argc; j++ )); do
echo "${argv[j]}"
done
В данном фрагменте кода argc
хранит количество аргументов, переданных скрипту, а argv
— массив всех аргументов. Затем, используя цикл, мы выводим каждый элемент массива argv
по индексу j
.
Вы можете использовать цикл for
, чтобы пройтись по всем переданным аргументам в скрипте Bash, используя переменную $#
, которая содержит количество аргументов. Пример ниже демонстрирует, как это сделать:
#! /bin/bash
for ((i=1; i<=$#; i++))
do
printf "${!i}\n"
done
При запуске этого скрипта с аргументами, например:
./test.sh 1 2 '3 4'
Вывод будет следующим:
1
2
3 4
В этом примере ${!i}
используется для получения значения i-го аргумента, где i
- это итератор цикла. Таким образом, цикл последовательно печатает каждый переданный аргумент на новой строке.
Как разобрать аргументы командной строки в Bash?
Как установить переменную на вывод команды в Bash?
Как изменить цвет вывода echo в Linux
Как работает "cat << EOF" в bash?
Передача параметров в функцию Bash