2009-08-26 7 views
124

(bearbeiten die Antwort zu passen) schneidenWie ein Array in bash

Mit Blick auf die „Array“ in der bash (1) man-Seite, ich habe nicht einen Weg finden, zu schneiden einen Bash-Array.

So kam ich mit dieser übermäßig komplizierten Funktion auf:

#!/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)" 
} 

wie folgt verwendet:

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

Gibt es einen besseren Weg, dies zu tun?

Antwort

182

Siehe den Parameter Expansion Abschnitt in der Bash man Seite. A[@] gibt den Inhalt des Feldes nimmt :1:2 ein Stück der Länge 2, bei Index beginnend 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 

zu beachten, dass die Tatsache, dass „abc“ ist ein Array-Element (und daß es einen zusätzlichen Zwischenraum) konserviert.

+2

Kühl. Ich schaute in die Array-Sektion und sah sie dort nicht. –

+11

Das ist albern Chen, warum sollte es in der Array-Sektion sein? * sarc – deltaray

+0

FYI: Es ist in der "Parameter Expansion" Abschnitt, zusammen mit vielen anderen raffinierten Tricks. –

41

Es gibt auch eine praktische Verknüpfung, um alle Elemente des Arrays beginnend mit dem angegebenen Index zu erhalten. Zum Beispiel wäre "$ {A [@]: 1}" der "Schwanz" des Arrays, also das Array ohne sein erstes Element.

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

Und während Sie dabei sind: echo $ {A [@] :: 1} "# 4' –

+3

Das ist großartig, aber es sollte beachtet werden, dass wenn es innerhalb einer Funktion verwendet wird, es leicht geändert werden muss, um zu lesen" $ {$ {@} [@]: 1} "'. –

0

Array wie (Aus der rebash Bibliothek) in Python Slicing:

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

Lets sagen, dass ich von dem Benutzer eine Reihe lese, dann will ich Element 3 bis 7, beide eingeschlossen, um zu sehen.

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


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

Die Slice-Syntax in Ihrem Code ist identisch mit der in der 8 Jahre alten akzeptierten Antwort. Ihre Antwort fügt nichts Neues hinzu. – melpomene