11

Как итерировать аргументы в Bash-скрипте

15

Я столкнулся с проблемой при написании сложной команды, которую хотел бы преобразовать в shell/bash скрипт. Я могу легко записать её с использованием $1:

foo $1 args -o $1.ext

Однако я хочу иметь возможность передавать несколько имен файлов на вход скрипту. Как правильно это сделать?

Кроме того, мне нужно обработать имена файлов, содержащие пробелы.

5 ответ(ов)

19

Используйте "$@" для представления всех аргументов:

for var in "$@"
do
    echo "$var"
done

Этот код будет перебирать каждый аргумент и выводить его на отдельной строке. $@ ведет себя похоже на $*, за исключением того, что, когда он заключен в кавычки, аргументы правильно разделяются, даже если они содержат пробелы:

sh test.sh 1 2 '3 4'
1
2
3 4
1

Обратите внимание, что ответ Роберта правильный и работает также в 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 "$@"'.

0

Для простых случаев вы также можете использовать команду shift. Она обрабатывает список аргументов как очередь. Каждый вызов shift удаляет первый аргумент, а индексы оставшихся аргументов уменьшаются на единицу.

Вот пример, который выводит все переданные аргументы:

# Этот код печатает все аргументы
while test $# -gt 0
do
    echo "$1"
    shift
done

В этом примере цикл продолжается до тех пор, пока количество аргументов больше нуля ($#), и каждый раз первый аргумент выводится на экран, после чего он удаляется из списка аргументов с помощью shift.

0

Вы также можете получить доступ к элементам массива, например, если не хотите перебирать все элементы с помощью цикла. Вот пример:

argc=$#
argv=("$@")

for (( j=0; j<argc; j++ )); do
    echo "${argv[j]}"
done

В данном фрагменте кода argc хранит количество аргументов, переданных скрипту, а argv — массив всех аргументов. Затем, используя цикл, мы выводим каждый элемент массива argv по индексу j.

0

Вы можете использовать цикл 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 - это итератор цикла. Таким образом, цикл последовательно печатает каждый переданный аргумент на новой строке.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь