Как разрезать массив в Bash

Глядя на раздел «Массив» на странице man bash (1), я не нашел способ срезать массив.

Поэтому я придумал эту чрезмерно сложную функцию:

#!/bin/bash # @brief: slice a bash array # @arg1: output-name # @arg2: input-name # @args: seq args # ---------------------------------------------- function slice() { local output=$1 local input=$2 shift 2 local indexes=$(seq $*) local -ii local tmp=$(for i in $indexes do echo "$(eval echo \"\${$input[$i]}\")" done) local IFS=$'\n' eval $output="( \$tmp )" } 

Используется следующим образом:

 $ A=( foo bar "abc" 42 ) $ slice BA 1 2 $ echo "${B[0]}" # bar $ echo "${B[1]}" # abc 

Есть лучший способ сделать это?

См. Раздел « Расширение параметров » на странице управления Bash. A[@] возвращает содержимое массива :1:2 принимает срез длиной 2, начиная с индекса 1.

 A=( foo bar "abc" 42 ) B=("${A[@]:1:2}") C=("${A[@]:1}") # slice to the end of the array echo "${B[@]}" # bar abc echo "${B[1]}" # abc echo "${C[@]}" # bar abc 42 echo "${C[@]: -2:2}" # abc 42 # The space before the - is necesssary 

Обратите внимание, что факт, что «abc» является одним элементом массива (и содержит лишнее пространство), сохраняется.

Существует также удобный ярлык для получения всех элементов массива, начиная с указанного индекса. Например, «$ {A [@]: 1}” будет «хвостом» массива, то есть массивом без его первого элемента.

 version=4.7.1 A=( ${version//\./ } ) echo "${A[@]}" # 4 7 1 B=( "${A[@]:1}" ) echo "${B[@]}" # 7 1 

Разбиение массива, как в Python (из библиотеки rebash ):

 array_slice() { local __doc__=' Returns a slice of an array (similar to Python). From the Python documentation: One way to remember how slices work is to think of the indices as pointing between elements, with the left edge of the first character numbered 0. Then the right edge of the last element of an array of length n has index n, for example: ``` +---+---+---+---+---+---+ | 0 | 1 | 2 | 3 | 4 | 5 | +---+---+---+---+---+---+ 0 1 2 3 4 5 6 -6 -5 -4 -3 -2 -1 ``` >>> local a=(0 1 2 3 4 5) >>> echo $(array.slice 1:-2 "${a[@]}") 1 2 3 >>> local a=(0 1 2 3 4 5) >>> echo $(array.slice 0:1 "${a[@]}") 0 >>> local a=(0 1 2 3 4 5) >>> [ -z "$(array.slice 1:1 "${a[@]}")" ] && echo empty empty >>> local a=(0 1 2 3 4 5) >>> [ -z "$(array.slice 2:1 "${a[@]}")" ] && echo empty empty >>> local a=(0 1 2 3 4 5) >>> [ -z "$(array.slice -2:-3 "${a[@]}")" ] && echo empty empty >>> [ -z "$(array.slice -2:-2 "${a[@]}")" ] && echo empty empty Slice indices have useful defaults; an omitted first index defaults to zero, an omitted second index defaults to the size of the string being sliced. >>> local a=(0 1 2 3 4 5) >>> # from the beginning to position 2 (excluded) >>> echo $(array.slice 0:2 "${a[@]}") >>> echo $(array.slice :2 "${a[@]}") 0 1 0 1 >>> local a=(0 1 2 3 4 5) >>> # from position 3 (included) to the end >>> echo $(array.slice 3:"${#a[@]}" "${a[@]}") >>> echo $(array.slice 3: "${a[@]}") 3 4 5 3 4 5 >>> local a=(0 1 2 3 4 5) >>> # from the second-last (included) to the end >>> echo $(array.slice -2:"${#a[@]}" "${a[@]}") >>> echo $(array.slice -2: "${a[@]}") 4 5 4 5 >>> local a=(0 1 2 3 4 5) >>> echo $(array.slice -4:-2 "${a[@]}") 2 3 If no range is given, it works like normal array indices. >>> local a=(0 1 2 3 4 5) >>> echo $(array.slice -1 "${a[@]}") 5 >>> local a=(0 1 2 3 4 5) >>> echo $(array.slice -2 "${a[@]}") 4 >>> local a=(0 1 2 3 4 5) >>> echo $(array.slice 0 "${a[@]}") 0 >>> local a=(0 1 2 3 4 5) >>> echo $(array.slice 1 "${a[@]}") 1 >>> local a=(0 1 2 3 4 5) >>> array.slice 6 "${a[@]}"; echo $? 1 >>> local a=(0 1 2 3 4 5) >>> array.slice -7 "${a[@]}"; echo $? 1 ' local start end array_length length if [[ $1 == *:* ]]; then IFS=":"; read -r start end <<<"$1" shift array_length="$#" # defaults [ -z "$end" ] && end=$array_length [ -z "$start" ] && start=0 (( start < 0 )) && let "start=(( array_length + start ))" (( end < 0 )) && let "end=(( array_length + end ))" else start="$1" shift array_length="$#" (( start < 0 )) && let "start=(( array_length + start ))" let "end=(( start + 1 ))" fi let "length=(( end - start ))" (( start < 0 )) && return 1 # check bounds (( length < 0 )) && return 1 (( start < 0 )) && return 1 (( start >= array_length )) && return 1 # parameters start with $1, so add 1 to $start let "start=(( start + 1 ))" echo "${@: $start:$length}" } alias array.slice="array_slice" 

Допустим, я читаю массив от пользователя, тогда я хочу видеть элементы с 3 по 7 включительно.

 cnt=0 while read var; do myarr[cnt]=$var cnt=$((cnt+1)) done echo ${myarr[@]:3:5} 
  • Многомерные массивы в Bash
  • Почему «int является uint == true» в C #
  • Накладные расходы .NET-массива?
  • Есть ли способ мгновенно генерировать массив, заполненный диапазоном значений в Swift?
  • Возrotation массива с использованием C
  • Столбец Access Array в Spark
  • Java: каково большое время для объявления массива размера n?
  • Индекс массива не связан с C
  • Как хранятся 3D-массивы в C?
  • Вернуть индекс нажатой кнопки?
  • Невозможно циклически перебирать динамическую строку json в android
  • Давайте будем гением компьютера.