Skip to content

Test auf Array-Unterstützung durch Shell

Lösung:

Angenommen, Sie möchten sich auf Bourne-ähnliche Muscheln beschränken (viele andere Muscheln wie csh, tcsh, rc, es oder fish Arrays unterstützen, aber gleichzeitig ein Skript schreiben, das mit Bourne-ähnlichen Shells kompatibel ist, und das ist schwierig und im Allgemeinen sinnlos, da sie Interpreter für völlig unterschiedliche und inkompatible Sprachen sind), beachten Sie, dass es erhebliche Unterschiede zwischen den Implementierungen gibt.

Die Bourne-ähnlichen Shells, die Arrays unterstützen (in chronologischer Reihenfolge, wann die Unterstützung hinzugefügt wurde):

  • ksh88 (die letzte Entwicklung des ursprünglichen ksh, die erste, die Arrays implementiert, ksh88 wird immer noch gefunden als ksh auf den meisten traditionellen kommerziellen Unices, wo es auch die Basis für sh)

    • Arrays sind eindimensional
    • Arrays sind definiert als set -A array foo bar oder set -A array -- "$var" ... wenn du das nicht garantieren kannst $var startet nicht mit a - oder +.
    • Array-Indizes beginnen bei 0.
    • Einzelne Array-Elemente werden zugewiesen als a[1]=value.
    • Arrays sind spärlich. Das ist a[5]=foo funktioniert auch wenn a[0,1,2,3,4] sind nicht gesetzt und werden sie nicht gesetzt lassen.
    • ${a[5]} um auf das Element von Index 5 zuzugreifen (nicht unbedingt das 6. Element, wenn das Array spärlich ist). Die 5 es kann jeden arithmetischen Ausdruck geben.
    • Arraygröße und Index sind begrenzt (auf 4096).
    • ${#a[@]} ist die Anzahl der zugewiesenen Elemente im Array (nicht der größte zugewiesene Index).
    • es gibt keine Möglichkeit, die Liste der zugewiesenen Indizes zu kennen (außer die 4096 Elemente einzeln zu testen mit [[ -n "${a[i]+set}" ]]).
    • $a ist das gleiche wie ${a[0]}. Das heißt, Arrays erweitern irgendwie skalare Variablen, indem sie ihnen zusätzliche Werte geben.
  • pdksh und Derivate (das ist die Grundlage für die ksh und manchmal sh von mehreren BSDs und war die einzige Open-Source-ksh-Implementierung, bevor der Quellcode von ksh93 freigegeben wurde):

    Meistens wie ksh88 aber beachte:

    • Einige alte Implementierungen wurden nicht unterstützt set -A array -- foo bar, (das -- wurde dort nicht benötigt).
    • ${#a[@]} ist eins plus den Index des größten zugewiesenen Index. (a[1000]=1; echo "${#a[@]}" gibt 1001 aus, obwohl das Array nur ein Element hat.
    • in neueren Versionen ist die Array-Größe nicht mehr begrenzt (außer durch die Größe von Ganzzahlen).
    • aktuelle Versionen von mksh Lassen Sie sich von ein paar zusätzlichen Operatoren inspirieren bash, ksh93 oder zsh wie Aufgaben a la a=(x y), a+=(z), ${!a[@]} um die Liste der zugewiesenen Indizes zu erhalten.
  • zsh. zsh Arrays sind im Allgemeinen besser gestaltet und nehmen das Beste aus ksh und csh Arrays. Wie Sie der Ankündigung von zsh 2.0 im Jahr 1991 entnehmen können, wurde das Design eher von tcsh als von ksh inspiriert. Sie haben eine gewisse Ähnlichkeit mit ksh Arrays, aber mit erheblichen Unterschieden:

    • Indizes beginnen bei 1, nicht 0 (außer in ksh Emulation), die mit dem Bourne-Array übereinstimmt (die Positionsparameter [email protected], welcher zsh auch als sein $argv-Array verfügbar macht) und csh Arrays.
    • sie sind ein von normalen/skalaren Variablen getrennter Typ. Operatoren gelten für sie anders und wie Sie es allgemein erwarten würden. $a ist nicht gleich ${a[0]} wird aber auf die nicht leeren Elemente des Arrays erweitert ("${a[@]}" für alle Elemente wie in ksh).
    • sie sind normale Arrays, keine spärlichen Arrays. a[5]=1 funktioniert, weist aber allen Elementen von 1 bis 4 den leeren String zu, wenn sie nicht zugewiesen wurden. So ${#a[@]} (gleich wie ${#a} was in ksh die Größe des Elements von Index ist 0) ist die Anzahl der Elemente im Array und der größte zugewiesene Index.
    • assoziative Arrays werden unterstützt.
    • eine große Anzahl von Operatoren für die Arbeit mit Arrays wird unterstützt, zu groß, um sie hier aufzulisten.
    • Arrays definiert als a=(x y). set -A a x y funktioniert auch für die Kompatibilität mit ksh, aber set -A a -- x y wird nicht unterstützt, es sei denn in der ksh-Emulation (der -- wird in der zsh-Emulation nicht benötigt).
  • ksh93. (hier die neuesten Versionen beschreiben). ksh93, eine Neufassung von ksh von den ursprünglichen Autoren, lange überlegt Experimental- ist seit der Veröffentlichung als FOSS in immer mehr Systemen zu finden. Zum Beispiel ist es die /bin/sh (wo es die Bourne-Schale ersetzte, /usr/xpg4/bin/sh, die POSIX-Shell basiert immer noch auf ksh88) und ksh von Solaris 11. Seine Arrays erweitern und verbessern die von ksh88.

    • a=(x y) kann verwendet werden, um ein Array zu definieren, aber da a=(...) wird auch verwendet, um zusammengesetzte Variablen zu definieren (a=(foo=bar bar=baz)), a=() ist mehrdeutig und deklariert eine zusammengesetzte Variable, kein Array.
    • Arrays sind mehrdimensional (a=((0 1) (0 2))) und Array-Elemente können auch zusammengesetzte Variablen sein (a=((a b) (c=d d=f)); echo "${a[1].c}").
    • EIN a=([2]=foo [5]=bar) Syntax kann verwendet werden, um spärliche Arrays auf einmal zu definieren.
    • Größenbeschränkungen aufgehoben.
    • Nicht im Umfang von zsh, aber auch eine große Anzahl von Operatoren wird unterstützt, um Arrays zu manipulieren.
    • "${!a[@]}" um die Liste der Array-Indizes abzurufen.
    • assoziative Arrays werden auch als separater Typ unterstützt.
  • bash. bash ist die Shell des GNU-Projekts. Es wird verwendet als sh auf neueren Versionen von OS/X und einigen GNU/Linux-Distributionen. bash Arrays emulieren meistens ksh88 diejenigen mit einigen Funktionen von ksh93 und zsh.

    • a=(x y) unterstützt. set -A a x y nicht unterstützt. a=() erzeugt ein leeres Array (keine zusammengesetzten Variablen in bash).
    • "${!a[@]}" für die Indexliste.
    • a=([foo]=bar) Syntax unterstützt sowie einige andere von ksh93 und zsh.
    • jüngste bash Versionen unterstützen auch assoziative Arrays als separaten Typ.
  • yash. Es ist eine relativ neue, saubere, Multibyte-fähige POSIX-sh-Implementierung. Nicht weit verbreitet. Seine Arrays sind eine weitere saubere API, ähnlich wie zsh

    • Arrays sind nicht dünn
    • Array-Indizes beginnen bei 1
    • definiert (und deklariert) mit a=(var value)
    • eingefügte, gelöschte oder geänderte Elemente mit array eingebaut
    • array -s a 5 value um die 5 . zu ändernNS Element würde fehlschlagen, wenn dieses Element nicht zuvor zugewiesen wurde.
    • die Anzahl der Elemente im Array ist ${a[#]}, ${#a[@]} die Größe der Elemente als Liste.
    • Arrays sind ein separater Typ. Du brauchst a=("$a") um eine Skalarvariable als Array neu zu definieren, bevor Sie Elemente hinzufügen oder ändern können.
    • "$array" expandiert auf alle Elemente des Arrays unverändert, wodurch sie viel einfacher zu verwenden sind als in anderen Shells (cmd "$array" anrufen cmd mit den Elementen des Arrays als Argumente im Vergleich zu cmd "${array[@]}" in ksh/bash/zsh; zsh'S cmd $array ist nah, entfernt aber leere Elemente).
    • Arrays werden nicht unterstützt, wenn sie als . aufgerufen werden sh.

Daraus können Sie also erkennen, dass die Array-Unterstützung erkannt wird, was Sie tun können:

if (unset a; set -A a a; eval "a=(a b)"; eval '[ -n "${a[1]}" ]'
   ) > /dev/null 2>&1
then
  array_supported=true
else
  array_supported=false
fi

reicht nicht aus, um diese Arrays verwenden zu können. Sie müssten Wrapper-Befehle definieren, um Arrays als Ganzes und einzelne Elemente zuzuweisen, und stellen Sie sicher, dass Sie nicht versuchen, Arrays mit geringer Dichte zu erstellen.

Mögen

unset a
array_elements() { eval "REPLY="${#$1[@]}""; }
if (set -A a -- a) 2> /dev/null; then
  set -A a -- a b
  case ${a[0]}${a[1]} in
    --) set_array() { eval "shift; set -A $1"' "[email protected]"'; }
        set_array_element() { eval "$1[1+($2)]=$3"; }
        first_indice=0;;
     a) set_array() { eval "shift; set -A $1"' -- "[email protected]"'; }
        set_array_element() { eval "$1[1+($2)]=$3"; }
        first_indice=1;;
   --a) set_array() { eval "shift; set -A $1"' "[email protected]"'; }
        set_array_element() { eval "$1[$2]=$3"; }
        first_indice=0;;
    ab) set_array() { eval "shift; set -A $1"' -- "[email protected]"'; }
        set_array_element() { eval "$1[$2]=$3"; }
        first_indice=0;;
  esac
elif (eval 'a[5]=x') 2> /dev/null; then
  set_array() { eval "shift; $1=("'"[email protected]")'; }
  set_array_element() { eval "$1[$2]=$3"; }
  first_indice=0
elif (eval 'a=(x) && array -s a 1 y && [ "${a[1]}" = y ]') 2> /dev/null; then
  set_array() { eval "shift; $1=("'"[email protected]")'; }
  set_array_element() {
    eval "
      $1=(${$1+"${$1[@]}"'"})
      while [ "$(($2))" -ge  "${'"$1"'[#]}" ]; do
        array -i "$1" "$2" ""
      done'
    array -s -- "$1" "$((1+$2))" "$3"
   }
  array_elements() { eval "REPLY=${$1[#]}"; }
  first_indice=1
else
  echo >&2 "Array not supported"
fi

Und dann greifen Sie auf Array-Elemente mit . zu "${a[$first_indice+n]}", die ganze Liste mit "${a[@]}" und verwenden Sie die Wrapper-Funktionen (array_elements, set_array, set_array_element), um die Anzahl der Elemente eines Arrays (in $REPLY), setzen Sie das Array als Ganzes oder weisen Sie einzelne Elemente zu.

Den Aufwand wahrscheinlich nicht wert. Ich würde verwenden perl oder auf das Bourne/POSIX-Shell-Array beschränken: "[email protected]".

Wenn die Absicht besteht, eine Datei von der interaktiven Shell eines Benutzers zu beziehen, um Funktionen zu definieren, die intern Arrays verwenden, sind hier einige weitere Hinweise, die nützlich sein können.

Sie können konfigurieren zsh Arrays, um ähnlicher zu sein ksh Arrays in lokalen Gültigkeitsbereichen (in Funktionen oder anonymen Funktionen).

myfunction() {
  [ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
  # use arrays of indice 0 in this function
}

Sie können auch emulieren ksh (Verbesserung der Kompatibilität mit ksh für Arrays und einige andere Bereiche) mit:

myfunction() {
  [ -z "$ZSH_VERSION" ] || emulate -L ksh
  # ksh code more likely to work here
}

In diesem Sinne und Sie sind bereit, die Unterstützung zu fallen für yash und ksh88 und ältere Versionen von pdksh Derivate, und solange Sie nicht versuchen, spärliche Arrays zu erstellen, sollten Sie in der Lage sein, konsequent Folgendes zu verwenden:

  • a[0]=foo
  • a=(foo bar) (aber nicht a=())
  • "${a[#]}", "${a[@]}", "${a[0]}"

in den Funktionen, die die emulate -L ksh, während zsh Der Benutzer verwendet seine Arrays normalerweise immer noch auf die zsh-Weise.

Sie können verwenden eval um die Array-Syntax auszuprobieren:

is_array_support() (
  eval 'a=(1)'
) >/dev/null 2>&1

if is_array_support; then
  echo support
else
  echo not
fi
Click to rate this post!
[Total: 0 Average: 0]



Anderer Beitrag

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.