2009-08-26 20 views
124

(編輯以適合的答案)怎麼給在bash數組

展望在bash(1)手冊頁的「陣列」一節,我沒有找到一個方法來切一個bash數組。

所以我想出了這個過於複雜的功能:

#!/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 

有沒有更好的方式來做到這一點?

回答

182

請參閱Bash man頁面中的Parameter Expansion部分。 A[@]返回數組的內容,:1:2需要長度爲2的切片,開始於索引1

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 

注意一個事實,即「ABC」是一個數組元素(和它包含一個額外的空間)是保存。

+2

很酷。我看着陣列部分,並沒有看到它。 – 2009-08-26 17:17:31

+11

這是愚蠢的陳,爲什麼它會在陣列部分? * sarc – deltaray 2014-05-01 02:54:41

+0

供參考:它在「參數擴展」部分,以及許多其他漂亮的技巧。 – 2014-05-16 22:27:51

41

還有一個方便的快捷方式來獲取以指定索引開始的數組的所有元素。例如「$ {A [@]:1}」將是數組的「尾部」,也就是沒有第一個元素的數組。

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

雖然你在它:'echo「$ {A [@] :: 1}」#4' – 2013-06-03 08:40:12

+3

這很好,但應該注意的是,如果在一個函數內使用,它必須稍微改變以讀取'' $ {$ {@} [@]:1}「'。 – 2015-11-11 00:15:41

0

陣列在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" 
0

可以說,我正在讀來自用戶的陣列,然後我想看元件3至7以下。

cnt=0 
while read var; 
    do 
    myarr[cnt]=$var 
    cnt=$((cnt+1)) 
    done 


echo ${myarr[@]:3:5} 
+0

代碼中的切片語法與8年前接受的答案中的切片語法相同。你的回答並不新鮮。 – melpomene 2017-04-07 13:23:36