Как извлечь последний позиционный аргумент функции или скрипта bash?

В bashчтение из каждого файла в цикле while, сравнение прочитанных строк и печать TRUEили FALSEсоответствующим образом:

while IFS= read -r -u3 line1; IFS= read -r -u4 line2; do
    [[ $line1 == $line2 ]] && echo TRUE || echo FALSE
done 3<file1 4<file2

Два вызова readсчитывают из дескриптора файла 3 и 4 соответственно. Файлы перенаправляются на них с двумя входными перенаправлениями в цикле.

16
27.09.2020, 23:31
5 ответов

Вы можете получить доступ к последнему элементу с помощью${argv[-1]}(bash 4.2 или выше )и удалить его из массива с помощью unsetвстроенной (bash 4.3 или выше):

last=${argv[-1]}
unset 'argv[-1]'

Кавычки вокруг argv[-1]необходимы, так как [...]является оператором glob, поэтому argv[-1]без кавычек может расширяться до argv-и/или argv1, если эти файлы существовали в текущем каталоге (или до ничего или вызвать ошибку, если они не были включены nullglob/ failglob).

27
18.03.2021, 23:01

Вы можете немного упростить, чтобы было проще для глаз, но основной метод не изменился (это может быть полезно, если у вас есть версия Bash, которая не поддерживает Предложение Quasímodo):

foo () {
    local argv=( "$@" )
    local last="${argv[$# - 1]}"
    argv=( "${argv[@]:0:$# - 1}" )
    echo "last: $last"
    echo "rest: ${argv[@]}"
}

Я признаю, что использование $#таким образом немного дерзко, но оно имеет то же значение, что и${#argv[@]}в этом конкретном примере , и более лаконично в коде.

6
18.03.2021, 23:01

Как насчет этого:

foo () {
    local last="${!#}"
    local argv=("${@:1:$#-1}")
    echo "last: $last"
    echo "rest: ${argv[@]}"
}
15
18.03.2021, 23:01

Для записи, в случае, если переключение на zshявляется опцией, в zshмассив позиционных параметров равен массиву $argv(массивы zsh являются истинными массивами, а с индексами, начинающимися с единицы, как и позиционные параметры ), так что здесь просто:

foo () {
    local last=$argv[-1]
    argv[-1]=()
    print -rC1 "last: $last" rest: ' - '$^argv
}

Хотя можно было бы и так:

foo () {
    print -rC1 "last: $argv[-1]" rest: ' - '$^argv[1,-2]
}

И если конечной целью является перебор позиционных параметров в обратном порядке:

for arg in "${(Oa)@}"; do
  something with "$arg"
done
3
18.03.2021, 23:01

Для более простого эквивалента ответа bxm используйтеset:

pop() {
  last="${!#}"  # see man bash, search for "indirect expansion"
  set -- "${@:1:$#-1}"

  printf 'not last: %s\n' "$@"
  printf 'last: %s\n' "${last}"
}

pop 1 2 3 4
# prints:
# not last: 1
# not last: 2
# not last: 3
# last: 4

Здесь ${!#}— расширение косвенного параметра (поиск «косвенного расширение» в man bash), а set -- ARGS...устанавливает новые значения аргументы($1и т. д. )к заданным аргументам.

Примечательно, что ${!#}и нарезка массива являются башизмами, но set --является переносим на любую оболочку POSIX.

0
18.03.2021, 23:01

Теги

Похожие вопросы