Kabuk ile dizi desteği testi


12

Komut satırında yerel Bourne benzeri kabuk tarafından dizi desteği için test etmenin kısa bir yolu var mı?

Bu her zaman mümkündür:

$ arr=(0 1 2 3);if [ "${arr[2]}" != 2 ];then echo "No array support";fi

veya $SHELLkabuk sürümü için test :

$ eval $(echo "$SHELL --version") | grep version

ve sonra sayfaya erişebileceğimi varsayarak, man sayfasını okudum. (Orada yazarken, /bin/bashBourne benzeri tüm mermilerin uzun seçeneği kabul ettiğini varsayıyorum, örneğin--version ksh için kırıldığında .)

Katılımsız ve komut dosyasının başında veya hatta çağırmadan önce bir Kullanım bölümüne dahil edilebilir basit bir test arıyorum.


Bourne benzeri mermilerle sınırlamak istediğini sanıyorum.
Stéphane Chazelas

@ StéphaneChazelas: Evet, çekirdek grubundan (kapsamlı olmayan) bahsediyorsanız: sh, csh, ksh, tcsh, bash, zsh ve yakın arkadaşlardan oluşur. Yash'ın bu takımyıldızda nerede olduğunu bilmiyorum.
Cbhihe

2
cshbir bourne kabuğu değildir. tcshbiri de değil ( cshbazı hatalar düzeltildi)
cas

1
Not $SHELLkullanıcının tercih edilen kabuk gibi $EDITORonun tercih edilen metin editörü. Şu anda çalışan kabuk ile ilgisi yoktur.
Stéphane Chazelas

1
eval$SHELL --versionkabuk kodu olarak çıktısını kullanmak mantıklı değil.
Stéphane Chazelas

Yanıtlar:


12

Eğer Bourne gibi kabuklarına (diğer birçok kabukları sevmeye kısıtlamak istediğiniz varsayarsak csh, tcsh, rc, esveya fishdestek diziler ama kabukları benzeri Bourne aynı anda uyumlu bir senaryo yazıyor ve bunlar tamamen farklı ve için tercümanlar gibi bu zor ve genellikle anlamsızdır uyumsuz diller), uygulamalar arasında önemli farklılıklar olduğunu unutmayın.

Dizileri destekleyen Bourne benzeri kabuklar şunlardır:

  • ksh88(bu, dizileri uygulayan ilk koddur, ksh88, yine kshde temelini oluşturan çoğu geleneksel ticari Unices'te hala bulunur sh)

    • diziler tek boyutludur
    • Diziler olarak tanımlanır set -A array foo barya set -A array -- "$var" ...sen garanti edemez eğer $varbir ile başlamaz -ya +.
    • Dizi indeksleri başlar 0.
    • Tek tek dizi öğeleri olarak atanır a[1]=value.
    • diziler seyrek. Bu, ayarlanmamış a[5]=fooolsa bile çalışacak a[0,1,2,3,4]ve onları ayarsız bırakacaktır.
    • ${a[5]}indice 5 elemanına erişmek için (dizi seyrek ise 6. eleman olmak zorunda değildir). 5Aritmetik ifadesi olabilir.
    • dizi boyutu ve alt simge sınırlıdır (4096 ile).
    • ${#a[@]} dizideki atanan öğenin sayısıdır (atanan en büyük dizin değil).
    • atanan aboneliklerin listesini bilmenin bir yolu yoktur (4096 öğelerini ayrı ayrı test etmek dışında [[ -n "${a[i]+set}" ]]).
    • $aile aynıdır ${a[0]}. Yani diziler skaler değişkenleri bir şekilde ekstra değerler vererek genişletir.
  • pdkshve türevler ( bazı BSD'lerin ve kshbazen de temelini oluşturur ve shksh93 kaynağı serbest bırakılmadan önceki tek açık kaynak ksh uygulamasıdır):

    Çoğunlukla gibi ksh88ama not:

    • Bazı eski uygulamalar desteklenmedi set -A array -- foo bar( --orada gerekli değildi).
    • ${#a[@]}bir artı atanan en büyük endeks endeksidir. ( a[1000]=1; echo "${#a[@]}"dizide yalnızca bir öğe olsa da 1001 çıktısı verilir.
    • daha yeni sürümlerde, dizi boyutu artık sınırlı değildir (tamsayıların boyutu dışında).
    • son sürümlerini mkshilham birkaç ekstra operatörler bash, ksh93ya zsha la atamaları gibi a=(x y), a+=(z), ${!a[@]}atanan endeksleri listesini almak için.
  • zsh. zshdiziler genellikle daha iyi tasarlanır ve en iyi şekilde kshve cshdizilerden yararlanır. Bunlar benzer kshancak önemli farklılıklar var:

    • Endeksler 0'da başlar ( kshöykünme hariç ), Bourne dizisiyle ( zsh$ argv dizisi olarak da ortaya çıkan $ @ konum parametreleri ) ve cshdizilerle tutarlıdır .
    • normal / skaler değişkenlerden ayrı bir türdür. Operatörler onlara farklı ve genel olarak beklediğiniz gibi uygulanır. $aile aynı değildir ${a[0]}ancak dizinin boş olmayan öğelerine (in "${a[@]}"gibi tüm öğeler için) genişler ksh.
    • seyrek diziler değil, normal dizilerdir. a[5]=1çalışır, ancak atanmamışlarsa 1'den 4'e kadar tüm öğeleri boş dizeye atar. Yani ${#a[@]}( ${#a}ksh cinsinden indice 0 öğesinin boyutuyla aynıdır ) dizideki eleman sayısı ve atanan en büyük indekstir.
    • çağrışımsal diziler desteklenir.
    • dizilerle çalışmak için çok sayıda operatör desteklenir, burada listelenemeyecek kadar büyük.
    • olarak tanımlanan diziler a=(x y). set -A a x yAyrıca çalışır, ancak set -A a -- x yksh öykünmesinde ( --zsh öykünmesinde gerekli değildir) desteklenmez.
  • ksh93. (burada en son sürümleri açıklar). ksh93, uzun süredir düşünülen deneysel artık FOSS olarak piyasaya sürüldüğünden daha fazla sistemde bulunabilir. Örneğin, bu kadar /bin/sh(Bourne kabuğu, ikame burada /usr/xpg4/bin/shPOSIX kabuk halen dayanmaktadır ksh88) ve kshbir Solaris 11. Dizileri ksh88'leri genişletir ve geliştirir.

    • a=(x y)diziyi tanımlamak için kullanılabilir, ancak a=(...)bileşik değişkenleri ( a=(foo=bar bar=baz)) tanımlamak için de kullanıldığından a=()belirsizdir ve dizi değil bileşik bir değişken bildirir.
    • diziler çok boyutlu ( a=((0 1) (0 2))) ve dizi elemanları da bileşik değişkenler ( a=((a b) (c=d d=f)); echo "${a[1].c}") olabilir.
    • a=([2]=foo [5]=bar)Seyrek dizileri bir kerede tanımlamak için bir sözdizimi kullanılabilir.
    • Boyut sınırlamaları kaldırıldı.
    • zshDizileri manipüle etmek için değil , çok sayıda operatör de destekledi.
    • "${!a[@]}" dizi indekslerinin listesini almak için.
    • ilişkilendirilebilir diziler ayrı bir tür olarak da desteklenir.
  • bash. bashGNU projesinin kabuğu. Sanki kullanılır shOS / X ve bazı GNU / Linux dağıtımları son sürümlerinde. bashdiziler çoğunlukla taklit ksh88bazı özellikleri ile olanları ksh93ve zsh.

    • a=(x y)destekledi. set -A a x y değil destekledi. a=()boş bir dizi oluşturur (içinde bileşik değişkenler yoktur bash).
    • "${!a[@]}" endeksler listesi için.
    • a=([foo]=bar)sözdizimi ve yanı sıra ksh93ve diğer birkaç destekledi zsh.
    • son bashsürümler ayrı bir tür olarak ilişkilendirilebilir dizileri de destekler.
  • yash. Nispeten yeni, temiz, çok baytlı bir POSIX sh uygulamasıdır. Geniş kullanımda değil. Dizileri benzer başka bir temiz APIzsh

    • diziler seyrek değildir
    • Dizi indeksleri 1'den başlar
    • ile tanımlanmış (ve beyan edilmiş) a=(var value)
    • arrayyerleşik ile eklenen, silinen veya değiştirilen öğeler
    • array -s a 5 valueöğenin önceden atanmamış olması durumunda 5. öğenin değiştirilmesi başarısız olur.
    • dizideki elementlerin sayısı ${a[#]}, ${#a[@]}bir liste olarak elemanlarının boyutu olan.
    • diziler ayrı bir türdür. a=("$a")Öğeleri ekleyebilmeniz veya değiştirebilmeniz için önce bir skaler değişkeni dizi olarak yeniden tanımlamanız gerekir .
    • olarak çağrıldığında diziler desteklenmez sh.

Böylece, bundan sonra yapabileceğiniz dizi desteği algılamayı görebilirsiniz:

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

bu dizileri kullanabilmek için yeterli değildir. Dizileri bir bütün ve tek tek öğeler olarak atamak için sarıcı komutları tanımlamanız ve seyrek diziler oluşturmaya çalışmadığınızdan emin olmanız gerekir.

Sevmek

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"' "$@"'; }
        set_array_element() { eval "$1[1+(\$2)]=\$3"; }
        first_indice=0;;
     a) set_array() { eval "shift; set -A $1"' -- "$@"'; }
        set_array_element() { eval "$1[1+(\$2)]=\$3"; }
        first_indice=1;;
   --a) set_array() { eval "shift; set -A $1"' "$@"'; }
        set_array_element() { eval "$1[\$2]=\$3"; }
        first_indice=0;;
    ab) set_array() { eval "shift; set -A $1"' -- "$@"'; }
        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=("'"$@")'; }
  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=("'"$@")'; }
  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

Sonra dizi ile öğelerine erişmek "${a[$first_indice+n]}"ile tüm listeyi "${a[@]}"ve sarıcı işlevleri kullanabilirsiniz ( array_elements, set_array, set_array_element) (bir dizinin elemanlarının sayısını elde $REPLY), bir bütün ya da atama bireysel elemanlar olarak dizi ayarlayın.

Muhtemelen çabaya değmez. Kullanayım perlBourne / POSIX kabuk dizisine veya sınır: "$@".

Amaç, dahili olarak dizileri kullanan işlevleri tanımlamak için bir kullanıcının etkileşimli kabuğu tarafından kaynaklanacak bir dosyaya sahip olmaksa, işinize yarayabilecek birkaç not daha vardır.

Dizileri yerel kapsamlardaki diziler zshgibi olacak şekilde yapılandırabilirsiniz ksh(işlevlerde veya anonim işlevlerde).

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

Ayrıca, aşağıdakilerle öykünebilir ksh( kshdiziler ve diğer birkaç alanla uyumluluğu iyileştirebilirsiniz ):

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

Bunu göz önünde bulundurarak ve türevlerin ve eski sürümlerinin desteğini bırakmaya istekli olursunuz yashve seyrek diziler oluşturmaya çalışmadığınız sürece, tutarlı bir şekilde şunları kullanabilmelisiniz:ksh88pdksh

  • a[0]=foo
  • a=(foo bar)(ama değil a=())
  • "${a[#]}", "${a[@]}","${a[0]}"

kullanıcı hala dizilerini normalde zsh yolunu kullanırken emulate -L ksh, bu işlevlerde zsh.


7

evalDizi sözdizimini denemek için kullanabilirsiniz :

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

if is_array_support; then
  echo support
else
  echo not
fi

2
ksh88dizileri destekler ancak desteklemez a=(). In ksh93, a=()değişken önceden dizi olarak bildirilmedikçe dizi değil bileşik değişken bildirir.
Stéphane Chazelas

2
Ayrıca dizi uygulamaları arasında önemli farklılıklar olduğunu unutmayın. Örneğin, bazılarının 0 ile başlayan dizi indeksleri vardır (bash, ksh, ksh öykünmesindeki zsh), bazıları birinden başlayan (zsh, yash). Bazıları normal diziler / listeler, bazıları seyrek dizilerdir (ksh veya bash gibi pozitif tamsayılarla sınırlı anahtarlara sahip ilişkisel diziler).
Stéphane Chazelas

Olarak yash, sen yapmıyorsun a[5]=1amaarray -s a 5 1
Stéphane Chazelas

@ StéphaneChazelas: Hassasiyet için teşekkürler. Benim durumumda her şey dizilerin (ilişkilendirilebilir ya da desteklenmiyor) desteklenip desteklenmediğine bağlı. Dizin tabanıyla ilgili ayrıntılar, katılımsız çalışacak bir komut dosyasında bile kolayca çözülebilir.
Cbhihe

@ StéphaneChazelas: Bileşik değişken ksh93beni şaşırttı, bana bununla ilgili belgelerin bir kısmını vermek ister misiniz? 1Çalışması için diziye ekliyorum .
cuonglm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.