Во-первых, обратите внимание, что $@
без кавычек не имеет смысла и не должно использоваться. $@
должен использоваться только в кавычках ( "$@"
) и в контекстах списка.
for i in "$@"
квалифицируется как контекст списка, но здесь, для обхода позиционных параметров, каноническая, наиболее переносимая и более простая форма:
for i
do something with "$i"
done
Теперь, чтобы перебрать элементы, начиная со второго, каноническим и наиболее переносимым способом является использование shift
:
first_arg=$1
shift # short for shift 1
for i
do something with "$i"
done
После shift
этого то, что раньше $1
было удалено из списка (но мы его сохранили $first_arg
), а то, что было раньше, $2
теперь есть $1
. Позиционные параметры были смещены 1
влево (используйте shift 2
для смещения на 2 ...). Таким образом, по сути, наш цикл переходит от того, что раньше было вторым аргументом к последнему.
С bash
(и zsh
и ksh93
, но это все) альтернативой является:
for i in "${@:2}"
do something with "$i"
done
Но обратите внимание, что это не стандартный sh
синтаксис, поэтому его не следует использовать в сценарии, который начинается с #! /bin/sh -
.
В zsh
или yash
вы также можете сделать:
for i in "${@[3,-3]}"
do something with "$i"
done
цикл с 3-го по 3-й последний аргумент.
В zsh
, $@
также известный как $argv
массив. Таким образом, чтобы вытолкнуть элементы из начала или конца массивов, вы также можете сделать:
argv[1,3]=() # remove the first 3 elements
argv[-3,-1]=()
( shift
также может быть написано 1=()
в zsh
)
В bash
, вы можете назначить только $@
элементы со set
встроенными, так что выкинуть 3 элемента с конца, это будет что-то вроде:
set -- "${@:1:$#-3}"
И чтобы перейти с 3-го на 3-е последнее:
for i in "${@:3:$#-5}"
do something with "$i"
done
POSIXly, чтобы вытолкнуть последние 3 элемента "$@"
, вам нужно использовать цикл:
n=$(($# - 3))
for arg do
[ "$n" -gt 0 ] && set -- "$@" "$arg"
shift
n=$((n - 1))
done
for ((i=2; i<=$#; i++)); do something with "${!i}"; done
Я думаю, что вы хотите
shift
встроенный. Переименовывает$2
в$1
,$3
в$2
и т. Д.Так:
источник
for
цикл, затем вы просто циклически проходите через $ @. Послеshift
звонка $ @ должно бытьarg2_1 arg2_2 arg2_3...
Всегда есть подход пещерного человека:
Это оставляет
$@
нетронутым (в случае, если вы хотите использовать его позже), и просто перебирает каждый аргумент, но не обрабатывает первый.источник
В bash вы также можете написать этот цикл с явной индексацией:
Это перебирает все аргументы от второго до последнего. Если вы хотите исключить последний аргумент, просто сделайте это
и если вы хотите принять любой другой аргумент, напишите его как
За этим стоит арифметическая версия
for
встроенной функции в сочетании с числом аргументов$#
и косвенной переменной${…}
.Одним из хороших приложений является то, что вы можете использовать это, чтобы решить, внутри цикла, будет ли данная опция принимать аргумент, следующий за ней, в качестве значения. Если это так, увеличивайте
i
(например, записывайте: $((++i))
), чтобы использовать следующее значение, и пропустите его во время итерации.источник