Bash: срез позиционных параметров

Вопрос или проблема

Как мне получить часть $@ в Bash, не копируя сначала все позиционные параметры в другой массив, как это?

argv=( "$@" )
echo "${argv[@]:2}";

Вы можете использовать тот же формат, что и для любого другого массива. Чтобы извлечь 2-й и 3-й элементы из $@, вы можете сделать следующее:

echo "${@:1:2}"
          - -
          | |----> длина среза
          |------> начальный индекс среза 

Больше примеров срезов массивов в bash

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

Итак, вот некоторые примеры:

Срез из массива входных аргументов, @, который обычно видно и который просто доступен как $@:

# базовый формат среза массива 1: взять определённую длину, начиная с определённого
# индекса
echo "${@:2:5}"
#         │ │
#         │ └────> длина среза
#         └──────> начальный индекс среза 

# базовый формат среза массива 2: взять все оставшиеся элементы массива, начиная с
# определённого индекса и до конца
echo "${@:2}"
#         │
#         │
#         └──────> начальный индекс среза 

Ещё напоминания о массивах для себя:

Следующие напоминания о массивах будут полезны и другим, кто зашёл на эту страницу.

# сохранить срез из массива в новый массив
new_array=("${@:4}")

# вывести весь массив (используйте "*" для генерации списка
# с пробелами между элементами, а не "@", что будет генерировать отдельные аргументы)
echo "new_array = ${new_array[*]}"

Вот пример запуска с универсальным срезом массива и доступом к элементам массива в bash, вдохновлённый этим источником:

(Используйте @ как массив входных аргументов, если это необходимо, вместо a ниже, в зависимости от вашего случая использования)

a=(one two three four five six)   # определить новый массив, `a`, с 6 элементами
echo "$a"           # вывести первый элемент массива a
echo "${a}"         # вывести первый элемент массива a
echo "${a[0]}"      # вывести первый элемент массива a
echo "${a[1]}"      # вывести *второй* элемент массива a
echo "${#a[@]}"     # вывести количество элементов в массиве a
echo "${a[@]:1:3}"  # вывести со 2-го по 4-й элементы; то есть 3 элемента
                    # начиная с индекса 1, включая, то есть: индексы 1, 2 и 3
                    # (вывод: `two three four`)
echo "${a[@]:1}"    # вывести со 2-го элемента и далее

Запустите всё

Скопируйте и вставьте все части кода выше в файл с именем array_slicing_demo.sh, и пометьте его как исполняемый с помощью chmod +x array_slicing_demo.sh, чтобы вы могли его запустить. Или просто загрузите мой демон array_slicing_demo.sh из моего eRCaGuy_hello_world репозитория здесь.

Затем выполните его следующим образом:

./array_slicing_demo.sh a b c d e f g h i j k

…и вы увидите следующий вывод:

b c d e f
b c d e f g h i j k
new_array = d e f g h i j k
one
one
one
two
6
two three four
two three four five six

Ссылки

  1. Bash: срез позиционных параметров
  2. Единственные скобки в присваивании переменным bash

Ключевые слова: доступ к массивам в bash; индексация массивов bash; доступ к элементам в массивах bash; срез массивов bash; вывод массивов в bash; вывод элементов массива в bash

Я обычно делаю так:

somefunc() {
    local message="$1"
    shift
    echo "message = $message"
    echo "other   = $@"
}
somefunc first second third goforth

что напечатает:

message = first
other   = second third goforth

Вы можете развить эту концепцию, сделав shift после второго, третьего и так далее аргумента

Что касается параметров функций, ответ с echo "${@:1:2}" вообще не сработал для меня. Кроме того, я хотел обрезать первый элемент, так как это был другой параметр. Что сработало:

function foo(){ #принимает один параметр + массив параметров
  local param1="$1".                   #первый параметр
  local -a tmp=( "${@}" )              #копируем все параметры
  local -a rem_params=( "${tmp[@]:1}") #обрезаем первый:работает!
# local -a rem_params=( "${@[@]:1}"  ) #НЕ РАБОТАЛО, ОШИБКА
# local -a rem_params=( "{@:1}"      ) #НЕ ОТРЕЗАЛО
  echo "${rem_params[@]}"
}

Возможно, я напишу, чтобы протестировать, как это работает с позиционными аргументами на уровне скрипта, но сейчас нет времени.

Ответ или решение

Как получить срез позиционных параметров в Bash

В Bash существует несколько способов работы с позиционными параметрами, но одной из наиболее популярных задач является извлечение среза из массивов аргументов командной строки без необходимости их предварительного копирования в другой массив. Рассмотрим, как это можно сделать эффективно.

Обзор позиционных параметров

Позиционные параметры в Bash обозначаются как $@, $1, $2 и т. д. $@ представляет собой массив всех переданных аргументов. Несмотря на то что $@ часто используется для обращения к позиционным параметрам, его можно применять аналогично любому другому массиву, что может создавать путаницу.

Синтаксис для получения срезов

Чтобы выполнить срез позиционных параметров, можно воспользоваться следующей конструкцией:

echo "${@:starting_index:length}"
  • starting_index — индекс, с которого начинается срез (обратите внимание, что индексация начинается с нуля).
  • length — количество элементов, которые вы хотите извлечь из массива.

Если нужно извлечь все оставшиеся элементы начиная с определённого индекса, используйте следующий синтаксис:

echo "${@:starting_index}"

Примеры использования

  1. Извлечение первого и второго аргументов:
echo "${@:1:2}"  # Это выведет второй и третий аргументы
  1. Извлечение аргументов начиная с третьего:
echo "${@:2}"    # Это выведет все аргументы начиная с третьего

Пример функции с использованием среза

Давайте рассмотрим пример функции, которая принимает один параметр и массив остальных параметров:

somefunc() {
    local message="$1"
    shift
    echo "message = $message"
    echo "other = $@"
}

Вызывая эту функцию:

somefunc first second third goforth

Вы получите следующий вывод:

message = first
other = second third goforth

Обработка срезов в функции

Если вам нужно работать с массивами в функции, можно использовать срезы, как показано в следующем примере:

function foo() {
    local param1="$1"                 # Первый параметр
    local -a rem_params=( "${@:2}" )  # Срез оставшихся параметров
    echo "${rem_params[@]}"
}

foo first second third forth

В этом примере функция foo извлекает все аргументы, начиная со второго, и выводит их.

Заключение

Таким образом, работа с позиционными параметрами в Bash становится гораздо проще, если вы знаете, как использовать срезы и массивы. Это позволяет избежать ненужного копирования параметров в новые массивы, что, в свою очередь, делает ваш код более эффективным и читаемым.

Эти приёмы могут быть полезны не только в скриптах, но и в более крупных проектах, где необходимо обрабатывать множество параметров, передаваемых функции или скрипту. Попробуйте применить эти методы в своих проектах, и вы заметите, как они упрощают вашу работу с аргументами командной строки.

Ресурсы для дальнейшего изучения

  1. Управление позиционными параметрами в Bash
  2. Bash Arrays and Slicing

Следуя этому руководству, вы сможете более эффективно работать с позиционными параметрами и добавлять гибкость в ваши скрипты Bash.

Оцените материал
Добавить комментарий

Капча загружается...