Bash에서 어레이를 슬라이스하는 방법
bash(1) man 페이지의 「Array」섹션을 참조해도, 어레이를 슬라이스 하는 방법을 찾을 수 없었습니다.
그래서 저는 이 지나치게 복잡한 기능을 생각해냈습니다.
#!/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 -i i
local tmp=$(for i in $indexes
do echo "$(eval echo \"\${$input[$i]}\")"
done)
local IFS=$'\n'
eval $output="( \$tmp )"
}
다음과 같이 사용:
$ A=( foo bar "a b c" 42 )
$ slice B A 1 2
$ echo "${B[0]}" # bar
$ echo "${B[1]}" # a b c
더 좋은 방법이 있을까요?
"Bash"의 "Parameter Exparameter expansionman
페이지입니다.A[@]
배열의 내용을 반환합니다.:1:2
인덱스 1부터 시작하는 길이 2의 슬라이스를 가져옵니다.
A=( foo bar "a b c" 42 )
B=("${A[@]:1:2}")
C=("${A[@]:1}") # slice to the end of the array
echo "${B[@]}" # bar a b c
echo "${B[1]}" # a b c
echo "${C[@]}" # bar a b c 42
echo "${C[@]: -2:2}" # a b c 42 # The space before the - is necesssary
주의해 주십시오.a b c
는, 1개의 어레이 요소(및 여분의 스페이스 포함)가 보존되고 있는 것입니다.
지정된 인덱스로 시작하는 배열의 모든 요소를 가져올 수 있는 편리한 단축키도 있습니다.예를 들어 "${A[@:1}"은 어레이의 "꼬리", 즉 첫 번째 요소가 없는 어레이가 됩니다.
version=4.7.1
A=( ${version//\./ } )
echo "${A[@]}" # 4 7 1
B=( "${A[@]:1}" )
echo "${B[@]}" # 7 1
Python과 같은 배열 슬라이싱(재플래시 라이브러리에서):
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"
@jandob의 대답에 영감을 받아 죽은 말을 물리칠 위험을 무릅쓰고 이 버전을 만들었습니다.
- 심플함(많이 가지고 있지 않음
shift
논리 또는 변수 재작성)을 자주 수행합니다. - 를 처리하지 않고 인용된 문자열을 존중합니다.
IFS
(-r
모드만). - 사용자가 다음을 지정할 수 있습니다.
[start, end)
슬라이스 또는[start, length]
슬라이스 경유의-l
플래그를 설정합니다. - 할 수 있다
echo
결과 어레이(디폴트 동작) 또는 발신측 부모에서 사용하기 위해서 새로운 어레이로 「리턴」합니다( 를 개입시켜).-r slicedArray
).
참고: namerefs는 Bash > = 4.3에서만 지원됩니다.이전 버전의 Bash(Brew의 bash가 없는 Mac)를 지원하려면 대신 indirection을 사용해야 합니다. temp var를 사용하여 배열 매개 변수에 액세스합니다.declare arrValuesCmd="$1[@]"; declare arr=("${!arrValuesCmd}")
반환값에는 eval을 사용합니다.eval $retArrName='("${newArr[@]}")'
(어레이 선언 주위에 작은 따옴표를 붙입니다).
array.slice() {
# array.slice [-l] [-r returnArrayName] myArray 3 5
# Default functionality is to use second number as end index for slice (exclusive).
# Can instead use second number as length by passing `-l` flag.
# `echo` doesn't maintain quoted entries, so pass in `-r returnArrayName` to keep them.
declare isLength
declare retArrName
declare OPTIND=1
while getopts "lr:" opt; do
case "$opt" in
l)
# If `end` is slice length instead of end index
isLength=true
;;
r)
retArrName="$OPTARG"
;;
esac
done
shift $(( OPTIND - 1 ))
declare -n arr="$1"
declare start="$2"
declare end="$3"
declare arrLength="${#arr[@]}"
declare newArr=()
declare newArrLength
# Bash native slicing:
# Positive index values: ${array:start:length}
# Negative index values: ${array: start: length}
# To use negative values, a space is required between `:` and the variable
# because `${var:-3}` actually represents a default value,
# e.g. `myVar=${otherVal:-7}` represents (pseudo-code) `myVar=otherVal || myVar=7`
if [[ -z "$end" ]]; then
# If no end is specified (regardless of `-l`/length or index), default to the rest of the array
newArrLength="$arrLength"
elif [[ -n "$isLength" ]]; then
# If specifying length instead of end-index, use native bash array slicing
newArrLength="$(( end ))"
else
# If specifying end-index, use custom slicing based on a range of [start, end):
newArrLength="$(( end - start ))"
fi
newArr=("${arr[@]: start: newArrLength}")
if [[ -n "$retArrName" ]]; then
declare -n retArr="$retArrName"
retArr=("${newArr[@]}")
else
echo "${newArr[@]}"
fi
}
예:
myArray=(x y 'a b c' z 5 14) # length=6
array.slice myArray 2 4
# > a b c z
array.slice -l myArray 3 2
# > z 5
# Note: Output was manually quoted to show the result more clearly.
# Actual stdout content won't contain those quotes, which is
# why the `-r returnArray` option was added.
array.slice -r slicedArray myArray -5 -3 # equivalent of [2, 4)
# > (null)
echo -e "myArray (length=${#myArray[@]}): ${myArray[@]} \nslicedArray (length=${#slicedArray[@]}): ${slicedArray[@]}"
# > myArray (length=6): x y 'a b c' z 5 14
# > slicedArray (length=2): 'a b c' z
array.slice -lr slicedArray myArray -5 3 # length instead of index, equivalent of [2, 5)
# > (null)
echo -e "myArray (length=${#myArray[@]}): ${myArray[@]} \nslicedArray (length=${#slicedArray[@]}): ${slicedArray[@]}"
# > myArray (length=6): x y 'a b c' z 5 14
# > slicedArray (length=3): 'a b c' z 5
언급URL : https://stackoverflow.com/questions/1335815/how-to-slice-an-array-in-bash
'programing' 카테고리의 다른 글
큰 테이블의 VARCHAR 컬럼 크기를 늘릴 때 문제가 발생합니까? (0) | 2023.04.11 |
---|---|
대소문자를 구분하지 않는 목록 검색 (0) | 2023.04.11 |
# 꺽쇠 괄호 < >와 따옴표 "를 사용하여 Import합니다. (0) | 2023.04.11 |
지정된 상대 경로 절대 경로 검색 방법 (0) | 2023.04.11 |
HTML 테이블을 Excel로 내보내기 - Office 2010에서 열리지 않음 (0) | 2023.04.11 |