Διαδρομές
/
Bash
Bash
/
Ύλη
/
Περισσότερα για τους πίνακες
Πε

Περισσότερα για τους πίνακες σε Bash

{one: "1 άσκηση", other: "%{count} ασκήσεις"}

Σχετικά με την έννοια Περισσότερα για τους πίνακες

Γνωρίσαμε τους πίνακες στο κεφάλαιο Πίνακες. Αυτό το κείμενο θα δείξει περισσότερους τρόπους χρήσης των πινάκων.

Συνένωση των στοιχείων ενός πίνακα σε μία συμβολοσειρά

Στο προηγούμενο κεφάλαιο για τους πίνακες, είδες το "${myarray[@]}", με τη θέση @, να χρησιμοποιείται για να επεκτείνει τον πίνακα στα επιμέρους στοιχεία. Αλλά μερικές φορές θέλεις να ενώσεις όλα τα στοιχεία σε μία μόνο συμβολοσειρά. Γι’ αυτό, χρησιμοποίησε τη θέση *:

echo "${myarray[*]}"

Είναι απαραίτητο να περικλείσεις την επέκταση σε διπλά εισαγωγικά.

Το Bash χρησιμοποιεί τον πρώτο χαρακτήρα της ενσωματωμένης μεταβλητής IFS ως χαρακτήρα διαχωρισμού. Από προεπιλογή, το $IFS αποτελείται από διάστημα, tab και αλλαγή γραμμής.

myarray=(one two three four)
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one two three four"

Μπορούμε να τροποποιήσουμε τη μεταβλητή IFS ώστε να χρησιμοποιήσουμε διαφορετικό χαρακτήρα διαχωρισμού:

myarray=(one two three four)
IFS=","
mystring="${myarray[*]}"
declare -p mystring
# => declare -- mystring="one,two,three,four"
Advanced
Μπορούμε να το ενσωματώσουμε αυτό σε μια συνάρτηση. Κάνε κλικ για λεπτομέρειες.
join() {
    local IFS=$1
    shift
    local elements=("$@")
    echo "${elements[*]}"
}

join ":" "${myarray[@]}"     # note, the "@" index
# => "one:two:three:four"

Η τοπικοποίηση του IFS μέσα στη συνάρτηση σημαίνει ότι δεν χρειάζεται να αποθηκεύσουμε την παλιά τιμή και να την επαναφέρουμε στην προηγούμενη τιμή της στο καθολικό πεδίο.

Για μεγαλύτερη βελτίωση, η ειδική παράμετρος "$*", όταν μπει σε εισαγωγικά, έχει την ίδια λειτουργικότητα, οπότε δεν χρειάζεται να αποθηκεύσουμε αντίγραφο των ορισμάτων της συνάρτησης:

join() {
    local IFS=$1
    shift
    echo "$*"
}
Χωρίς να χρησιμοποιήσεις συνάρτηση, η τροποποίηση του IFS σε ένα υποκέλυφος είναι καλός τρόπος να αποφύγεις να το τροποποιήσεις στο τρέχον κέλυφος. Κάνε κλικ για λεπτομέρειες.
(IFS=","; echo "${myarray[*]}")

Οι παρενθέσεις δημιουργούν ένα υποκέλυφος (ένα αντίγραφο του τρέχοντος κελύφους). Όταν ολοκληρωθούν οι εντολές μέσα στις παρενθέσεις, το υποκέλυφος τερματίζεται και η τροποποιημένη μεταβλητή IFS εξαφανίζεται.

Σημείωσε ότι αυτό δεν θα δουλέψει: IFS="," echo "${myarray[*]}". Η επέκταση παραμέτρων εκτελείται πρώτα, πριν το κέλυφος εφαρμόσει την τροποποιημένη μεταβλητή IFS στην εντολή echo.

Τμήματα πίνακα

Μπορεί να έχεις δει την επέκταση παραμέτρων "${variable:offset:length}" που επεκτείνεται σε μια υποσυμβολοσειρά της τιμής της μεταβλητής. Το ίδιο μπορούμε να κάνουμε και με τους πίνακες, για να επεκτείνουμε ένα τμήμα του πίνακα.

myarray=(one two three four)

subarray=("${myarray[@]:0:2}")
declare -p subarray
# => declare -a subarray=([0]="one" [1]="two")

subarray=("${myarray[@]:1:3}")
declare -p subarray
# => declare -a subarray=([0]="two" [1]="three" [2]="four")

Αν παραλείψεις το μέρος του μήκους, σημαίνει "από το σημείο εκκίνησης μέχρι το τέλος του πίνακα":

subarray=("${myarray[@]:2}")
declare -p subarray
# => declare -a subarray=([0]="three" [1]="four")

Πέρασμα πίνακα σε συνάρτηση

Αυτό δεν είναι τόσο απλό όσο σε άλλες γλώσσες που μπορεί να ξέρεις. Υπάρχουν δύο βασικές τεχνικές για να περάσεις έναν πίνακα σε μια συνάρτηση.

Πέρασμα των στοιχείων

Στην πρώτη τεχνική, περνάς όλες τις τιμές του πίνακα και τις συγκεντρώνεις σε έναν τοπικό πίνακα μέσα στη συνάρτηση.

myfunc() {
    local array_copy=("$@")
    # do stuff with array_copy
    declare -p array_copy
}

array_original=(11 22 33 44)
myfunc "${array_original[@]}"

Ο πίνακας της συνάρτησης κρατά ένα αντίγραφο των τιμών. Οποιεσδήποτε αλλαγές γίνουν στον πίνακα μέσα στη συνάρτηση δεν αντανακλώνται στο εξωτερικό πεδίο.

Πέρασμα του ονόματος του πίνακα

Αυτή η τεχνική μοιάζει περισσότερο με τη δυνατότητα "πέρασμα με αναφορά" που μπορεί να ξέρεις από άλλες γλώσσες. Περνάς το όνομα του πίνακα ως συμβολοσειρά. Η συνάρτηση θα δημιουργήσει μια τοπική μεταβλητή με το χαρακτηριστικό "nameref". Αυτός ο τοπικός πίνακας και ο καθολικός πίνακας (του οποίου το όνομα περάσαμε) είναι ο ίδιος πίνακας.

myfunc() {
    # note the `-n` option
    local -n local_array=$1

    # do stuff with local_array
    for i in "${!local_array[@]}"; do
        printf '%d => %s\n' "$i" "${local_array[i]}"
    end

    # we can mutate it
    local_array+=(55 66 77)
}

array_original=(11 22 33 44)
myfunc "array_original"

# show the mutated array
declare -p array_original
# => declare -a array_original=([0]="11" [1]="22" [2]="33" [3]="44" [4]="55" [5]="66" [6]="77")

Τα namerefs δουλεύουν επίσης με συσχετιστικούς πίνακες και με μεταβλητές "scalar" (που περιέχουν μια τιμή συμβολοσειράς).

Note

Μέσα στη συνάρτηση, το declare -p local_array δεν είναι ιδιαίτερα χρήσιμο. Απλώς θα εμφανίσει declare -n local_array="array_original". Μπορείς να πάρεις λεπτομερείς πληροφορίες για τον πίνακα εξετάζοντας το όνομα του πίνακα που πέρασες: declare -p "$1"

Caution

Πρόσεξε ώστε ο τοπικός πίνακας να έχει διαφορετικό όνομα από τον πίνακα που πέρασες. Ο κώδικας θα δουλέψει ακόμα, αλλά θα εμφανίσει προειδοποιήσεις "circular name reference" σαν αυτή:

myfunc() {
    local -n a=$1
    local IFS=,
    echo "${a[*]}"
}

# same name as the function's local variable
a=(one two three)
myfunc a
bash: local: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
bash: warning: a: circular name reference
one,two,three

Οι παράμετροι θέσης είναι "σαν πίνακες"

Σε κελύφη που στοχεύουν να συμμορφώνονται μόνο με το πρότυπο POSIX (όπως το ash και το dash), δεν υπάρχουν πίνακες. Το πιο κοντινό που μπορείς να κάνεις είναι να χρησιμοποιήσεις τις παραμέτρους θέσης.

  • Οι παράμετροι θέσης προσπελαύνονται με θέση: $1, $2, κ.λπ.
  • Επεκτείνονται σε επιμέρους στοιχεία με το "$@"
  • Συνενώνονται σε μία μόνο συμβολοσειρά με το "$*"
  • Ο αριθμός των παραμέτρων είναι $#

Χρησιμοποίησε την εντολή set για να τους αναθέσεις τιμές:

set -- one two three
set -- "$@" four

for item in "$@"; do
    echo "do something with $item"
done

Αν στόχος σου είναι να γράψεις "φορητά" σενάρια κελύφους, θα χρησιμοποιήσεις τις παραμέτρους θέσης για να αποθηκεύσεις μια "λίστα" τιμών.

Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα