Bir bash dizisini ortadaki bir dizinde nasıl kaydırabilirim?


12
1  #!/bin/bash
2  # query2.sh
3
4  numbers=(53 8 12 9 784 69 8 7 1)
5  i=4
6
7  echo ${numbers[@]} # <--- this echoes "53 8 12 9 784 69 8 7 1" to stdout.
8  echo ${numbers[i]} # <--- this echoes "784" to stdout.
9
10 unset numbers[i]
11
12 echo ${numbers[@]} # <--- this echoes "53 8 12 9 69 8 7 1" to stdout.
13 echo ${numbers[i]} # <--- stdout is blank.

Neden, satır 13'te, dizinin satır 12'nin stdout'una göre güncellenmiş gibi göz önüne alındığında, stdout boş mu?

Bu nedenle, amaçlanan cevabı "69" almak için ne yapmalıyım?


1
Bu sorunun ima ettiği kodlama işinin türü göz önüne alındığında, uyarı almalısınız: bkz. Senaryomda bir sorun mu var veya Bash Python'dan çok daha yavaş mı?
Wildcard

Yanıtlar:


21

unsetbir öğeyi kaldırır. Kalan öğeleri yeniden numaralandırmaz.

declare -pTam olarak ne olacağını görmek için kullanabiliriz numbers:

$ unset "numbers[i]"
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")

numbersArtık bir elemanın olmadığını gözlemleyin 4.

Başka bir örnek

Gözlemek:

$ a=()
$ a[1]="element 1"
$ a[22]="element 22"
$ declare -p a
declare -a a=([1]="element 1" [22]="element 22")

Dizi abu dizi indeksleri birbirini takip gerektirmez 21. Bash boyunca herhangi bir öğe 2 yer alır.

Endekslerin yeniden numaralandırılmasını zorlamak için önerilen yöntem

numbersEksik öğe içeren dizi ile başlayalım 4:

$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")

Endekslerin değişmesini istiyorsak, o zaman:

$ numbers=("${numbers[@]}")
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [4]="69" [5]="8" [6]="7" [7]="1")

Şimdi bir eleman numarası var 4ve değeri var 69.

Bir öğeyi ve yeniden numaralandırma dizisini tek adımda kaldırmak için alternatif yöntem

Tekrar tanımlayalım numbers:

$ numbers=(53 8 12 9 784 69 8 7 1)

Yorumlarda Toby Speight tarafından önerildiği gibi , dördüncü elemanı kaldırmak ve geri kalan elemanları tek adımda yeniden numaralandırmak için bir yöntem:

$ numbers=("${numbers[@]:0:4}" "${numbers[@]:5}")
$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [4]="69" [5]="8" [6]="7" [7]="1")

Gördüğünüz gibi, dördüncü eleman kaldırıldı ve kalan tüm elemanlar yeniden numaralandırıldı.

${numbers[@]:0:4}dilimleri dizisi numbers: 0 öğesinden başlayarak ilk dört öğeyi alır.

Benzer şekilde, ${numbers[@]:5}dilim dizisi numbers: 5. öğeden başlayıp dizinin sonuna kadar devam eden tüm öğeleri alır.

Bir dizinin indekslerini alma

Değerler bir dizi ile elde edilebilir ${a[@]}. Bu değerlere karşılık gelen dizinleri (veya anahtarları ) bulmak için tuşunu kullanın ${!a[@]}.

Örneğin numbers, eksik öğeye sahip dizimizi tekrar düşünün 4:

$ declare -p numbers
declare -a numbers=([0]="53" [1]="8" [2]="12" [3]="9" [5]="69" [6]="8" [7]="7" [8]="1")

Hangi indekslerin atandığını görmek için:

$ echo "${!numbers[@]}"
0 1 2 3 5 6 7 8

Yine, 4endeksler listesinde eksik.

belgeleme

Gönderen man bash:

unsetYerleşik Dizileri kaldırmak için kullanılır. unset name[subscript]dizideki dizi öğesini yok eder subscript. İndekslenmiş dizilere negatif abonelikler, yukarıda açıklandığı gibi yorumlanır. Yol adı genişlemesinin neden olduğu istenmeyen yan etkilerden kaçınmak için özen gösterilmelidir. unset name, namebir dizinin unset name[subscript]nerede subscriptolduğu * veya nerede olduğunu ya da @dizinin tamamını kaldırır.


1
Kabuk dizisi sözdiziminin, benzer şekilde adlandırılmış değişkenlerle başa çıkmayı kolaylaştırmanın bir yolu olduğunu unutmayın. Dizinin kendisi yoktur ; aslında, siz yazdıktan sonra a=(), aaslında indekslerinden birine atanana kadar değişken hala tanımsızdır.
chepner

@ John1024: Bu cevap için teşekkür ederim. Bunu, istenen sonuca ulaşmak için önerilen bir cevabı içerecek şekilde genişletebilir misiniz?
Anthony Webber

@AnthonyWebber Tabii. Cevaba, endekslerin yeniden numaralandırılmasının nasıl zorlanacağını göstermek için bir bölüm ekledim.
John1024

2
Sadece alternatif bir yaklaşımdan bahsetmek unset numbers[4]gerekirse (bazı kodlar için daha uygun olabilir): bunun yerine, dilimleme kullanarak tüm diziyi atayın, yani numbers=("${numbers[@]:0:4}" "${numbers[@]:5}")(bir cevap olarak gönderirim, ancak doğru bir şekilde açıklamak için zamanım yok).
Toby Speight

@ John1024: Bunu yaptığınız için teşekkür ederiz. Ve thnx Toby :)
Anthony Webber

5

bashgibi kshdiziler, gerçekte diziler değildir, daha çok pozitif tamsayılarla (veya seyrek diziler olarak adlandırılan ) anahtarlarla ilişkilendirilmiş diziler gibidirler . Gerçek diziler bir kabuk, aşağıdaki gibi kabukları bir göz olabilir rc, es, fish, yash, zsh(hatta csh/ tcsho kabuklar kadar çok sorunları var gerçi onlar daha iyi kaçınılması konum).

İçinde zsh:

a=(1 2 3 4 5)
a[3]=() # remove the 3rd element
a[1,3]=() # remove the first 3 elements
a[-1]=() # remove the last element

(Zsh içinde, unset 'a[3]'aslında daha iyi uyumluluk için boş dizeye ayarladığını unutmayın ksh)

içinde yash:

a=(1 2 3 4 5)
array -d a 3 # remove the 3rd element
array -d a 1 2 3 # remove the first 3 elements
array -d a -1 # remove the last element

içinde fish(bir Bourne benzeri kabuk tersine bash/ ' zsh):

set a 1 2 3 4 5
set -e a[3] # remove the 3rd element
set -e a[1..3] # remove the first 3 elements
set -e a[-1] # remove the last element

içinde es( rcBourne benzeri değil)

a = 1 2 3 4 5
a = $a(... 2 4 ...) # remove the 3rd element
a = $a(4 ...) # remove the first 3 elements
a = $a(... `{expr $#a - 1}) # remove the last element
# or a convoluted way that avoids forking expr:
a = $a(... <={@{*=$*(2 ...); return $#*} $a})

içinde kshvebash

Aşağıdaki durumlarda dizileri normal diziler olarak kullanabilirsiniz:

a=("${a[@]}")

Ayrıca unutmayınız 0'dan başlamaz bitişik veya olmasın endeksler listesini yapmış olabilir her silme veya ekleme işlemleri sonrasında ksh/ bashdiziler 0'dan başladığı değil, 1 (hariç $@(bazı yönlerden)).

Bu aslında elemanları derler ve sırasıyla 0, 1, 2 ... dizinine taşır.

Ayrıca şunu belirtmeniz gerektiğini unutmayın number[i]:

unset 'number[i]'

Aksi takdirde, geçerli dizinde unset numberiçağrılan bir dosya olduğu gibi ele alınır numberi.

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.