Bir dizinin son elemanını bash ile okumanın bir yolu var mı?


68

5 elementli bir dizi varsa, örneğin:

[a][b][c][d][e]

Kullanarak echo ${myarray[4]}ne tutarsa ​​onu görebilirim.

Peki ya belirli bir dizideki elementlerin sayısını bilmiyorsam? Bilinmeyen bir uzunluk dizisinin son elemanını okumanın bir yolu var mı? yani herhangi bir dizi için sağdan sola ilk okuyan eleman mı?

Bunu nasıl yapılacağını bilmek istiyorum.


$@tam olarak bir dizi değil (abone olamaz). Bunun için, bir kabuk betiğine geçen son argümanı alma bölümüne bakın .
Tom Hale,

Yanıtlar:


89

Son öğeyi almak için yalnızca negatif bir dizini ${myarray[-1]} kullanabilirsiniz. Aynı şeyi ikinci sonuncusu için de yapabilirsiniz; Bash'te:

Dizine alınmış bir dizinin bir öğesine başvurmak için kullanılan alt simge, sıfırdan küçük bir sayıyı değerlendirirse, dizinin maksimum dizinden daha büyük bir değere göre yorumlanır, bu nedenle negatif dizinler dizinin sonundan geri sayılır ve -1 endeksi son elemanı ifade eder.

Aynı zamanda atama için çalışır. "İfade" derken gerçekten bir ifade demektir; dizinin uzunluğunu ${#myarray[@]}açıkça kullanarak hesaplayanlar da dahil olmak üzere dizini hesaplamak için herhangi bir aritmetik ifadeyi yazabilirsiniz .


2
İçeri bunu yapabilir kshve zshaynı zamanda.
Janis

5
Bununla zshbirlikte, varsayılan olarak diziler, aksine bashve ksh0 dizinli olduklarından farklı olarak 1 dizinlidir.
Stephen Kitt

2
Evet tabi ki; Bu sorunun kısa cevabı değişmez, ancak uzun formdan bahsedildiğinden beri, davranıştaki farklılığa işaret etmenin gerekli olduğunu düşündüm.
Stephen Kitt

22
Negatif endeks sadece bash 4.3 ve daha üstü için çalışır.
cuonglm

10
Mac OS X'te bulunan ve en az v10.11.5 sürümünde bulunan Bash sürümü yalnızca 3.2'dir, bu nedenle Mac'ler üzerinde çalışmaz.
Doktor J

45

Modern bash (v4.1 veya daha iyisi)

Son öğeyi index'de okuyabilirsiniz -1:

$ a=(a b c d e f)
$ echo ${a[-1]}
f

Bash sürüm 4.1-alpha ile başlayan negatif dizinleri kullanarak son dizinden sayısal olarak dizine alınmış dizilere erişim desteği .

Eski bash (v4.0 veya daha önceki)

Dizi uzunluğunu almalı ${#a[@]}ve son elemanı alabilmek için bir tanesini çıkarmalısınız:

$ echo ${a[${#a[@]}-1]}
f

Bash, dizi aboneliklerini aritmetik bir ifade olarak kabul ettiğinden, $((...))aritmetik değerlendirmeyi zorlamak gibi ek gösterimlere gerek yoktur .


sonuncusu benim için çalışmıyor; Bash v4.1.2 (1) kullanıyorum: son öğeyi yazdırmak yerine, tüm diziyi yazdırıyor.
Alexej Magura,

@ cuonglm'ın cevabı ancak işe yarıyor.
Alexej Magura,

modernBir versiyona hak kazanabilseydiniz cevap daha da iyi olurdu .
Samveen

1
Tam olarak cevap verenin mükemmel olması için gerekenler.
Samveen

1
Bunun için teşekkür ederim. Echo $ {a [$ (($ {# a [@]} - 1]))} 'ı kullanıyordum çünkü "bash, dizi abonelerini aritmetik bir ifade olarak ele alıyor" hakkında bir şey bilmiyordum.
Bruno Bronosky

15

bashdizi ataması, referans, negatif indeks ile belirsizleştirme yalnızca bash 4.3'te eklenmiştir . Eski sürümüyle, bashdizinde ifadeyi kullanabilirsinizarray[${#array[@]-1}]

Başka bir yol, eski sürümüyle de çalışır bash(bash 3.0 veya üstü ):

$ a=([a] [b] [c] [d] [e])
$ printf %s\\n "${a[@]:(-1)}"
[e]

veya:

$ printf %s\\n "${a[@]: -1}"
[e]

Ofset olumsuz kullanarak ayırmak gerekir :ile -karıştırılmamalıdır önlemek için :-genişleme.


1
Bunu yapın "${a[@]: -1}"ve aynı zamanda içinde bashve dışında da çalışacaktır . zshksh
Janis

Kornshell dokümanları ( www2.research.att.com/sw/download/man/man1/ksh.html ) tamamen belirtmektedir. (Dokümanlarını incelemedim zshya da bash; ama üç kabukta da test ettim.)
Janis

@Janis: bash belgelerini tekrar okudum, ayrıca bu konuda da bahsetti. Tekrar teşekkürler.
cuonglm

4

dizi

Bash'daki en eski alternatif (ler) (bash 3.0+):

$ a=(aa bb cc dd ee)
$ echo "${a[@]:(-1)}   ${a[@]: -1}   ${a[@]:(~0)}   ${a[@]:~0}"
ee   ee   ee   ee

Uzay yorumlanmasını önlemek için gereklidir :bir eksi ardından -genişlemesi olarak "${var:-abc}"(Kullanım Varsayılan Değerler).

Bu ~, aritmetik bir bitsel olumsuzlamadır (birinin tamamlayıcısına eşdeğerdir veya tüm bitleri çevirir ). Adam bash'tan:

ARİTMETİK DEĞERLENDİRME

      ! ~         logical and bitwise negation  

Bash-4.2 + 'dan beri:

$ echo "${a[-1]}   ${a[(~0)]}"
ee   ee

Bash 5.0+ 'dan beri:

$ echo "${a[~0]}"
ee

Tüm bash sürümleri için (eski bash):

$ echo "${a[   ${#a[@]}-1   ]}"    # spaces added **only** for readability
ee

@

Konumsal argümanlar için (bash 2.01'den beri):

$ set aa bb cc dd ee
$ echo "${@:(-1)} ${@:~0} ${@: -1} ${@:$#}   ${!#}"
ee ee ee   ee

Tüm mermiler için portatif bir çözüm eval kullanmaktır:

eval printf '"%s\n"' \"\${$#}\"

Bash 5+ sözdizimi için bir referansınız var mı? Ben her 58 örneklerini aradı ~içinde kılavuzda ve onu görmedik.
Tom Hale,

... ve nasıl yapıyorsunuz $@? bash: ${@[@]:(-1)}: bad substitution
Tom Hale,

1
Evet, bir man bashreferans var (@ başlığında genişletilmiş cevabı kontrol edin). @TomHale
Isaac

1
@Olduğu değil , bir dizi (iyi, değil tamamen bir dizi bash) ve indeksi (kabul etmez []bireysel argümanlar) simge. Kullanmanız ${@:(-1)}veya eşdeğeri gerekir . @Başlığında genişletilmiş girişi kontrol edin . @TomHale
Isaac

-2

Ayrıca bunu yapabilirsiniz:

$ a=(a b c d e f)
$ echo ${a[$(expr ${#a[@]} - 1)]}

Sonuç:

$ f

Yaptığınız şey, dizideki tüm öğelerin sayısını almak ve -1'i çıkarmaktır çünkü tüm öğeleri elde edersiniz, 0 olan dizi dizininden başlamazsınız.

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.