途中のインデックスでbash配列をシフトするにはどうすればよいですか?


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.

13行目でstdoutが空白になっているのはなぜですか。12行目のstdoutで配列が更新されているように見えるのを考えてみてください。

したがって、意図した答え「69」を取得するにはどうすればよいですか?


1
この質問が意味するコーディング作業のタイプを考慮すると、警告を出す必要があります。スクリプトに問題があるか、BashはPythonよりもはるかに遅いですか?を
ワイルドカード2017

回答:


21

unset要素を削除します。残りの要素の番号は付け直しません。

declare -p何が起こるかを正確に確認するために使用できます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")

守っていないnumbers、もはや要素を持っています4

もう一つの例

観察する:

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

配列にaは2から21までの要素はありません。Bashでは、配列のインデックスが連続している必要はありません。

インデックスの再番号付けを強制する推奨方法

numbers要素のない配列から始めましょう4

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

インデックスを変更する場合は、次のようにします。

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

要素番号が4あり、値があります69

1つの手順で要素を削除して配列の番号を付け直す別の方法

もう一度、定義しましょうnumbers

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

Toby Speightのコメントで示唆されているように、4番目の要素を削除し、残りの要素の番号をすべて1つのステップで再設定する方法:

$ 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")

ご覧のとおり、4番目の要素が削除され、残りのすべての要素の番号が付け直されました。

${numbers[@]:0:4}スライス配列numbers:要素0から始まる最初の4つの要素を取得します。

同様に、${numbers[@]:5}配列のスライスnumbers:要素5で始まり、配列の最後まで続くすべての要素を取得します。

配列のインデックスを取得する

配列のはで取得できます${a[@]}。これらの値に対応するインデックス(またはキー)を見つけるには、を使用します${!a[@]}

たとえば、numbers要素が欠落している配列をもう一度考えてみましょう4

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

どのインデックスが割り当てられているかを確認するには:

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

繰り返しますが、4はインデックスのリストにありません。

ドキュメンテーション

からman bash

unset組み込みは、配列を破壊するために使用されます。 unset name[subscript]インデックスの配列要素を破棄しますsubscript。インデックス付き配列への負の添え字は、上記のように解釈されます。パス名の展開による不要な副作用を回避するように注意する必要があります。 unset name、ここでname配列され、又はunset name[subscript]、ここsubscriptであり * 又は @、全体の配列を除去します。


1
シェル配列構文は、実際には、類似した名前の変数を簡単に処理できるようにするための方法であることに注意してください。配列自体はありません。実際、を書き込んだ後、実際にそのインデックスの1つに割り当てるまでa=()、変数aは未定義のままです。
chepner 2017

@ John1024:この回答をありがとうございます。意図した結果を達成するための推奨回答を含めるように拡張できますか?
アンソニーウェバー

@AnthonyWebberもちろん。回答にセクションを追加して、インデックスの再番号付けを強制する方法を示しました。
John1024

2
代わりのアプローチ(いくつかのコードに適している可能性があります)に言及するだけです:の代わりにunset numbers[4]、スライスを使用して配列全体を割り当てますnumbers=("${numbers[@]:0:4}" "${numbers[@]:5}")(つまり、回答として投稿しますが、適切に説明する時間はありません)。
Toby Speight 2017

@ John1024:ありがとうございます。そしてthnx Toby :)
Anthony Webber

5

bashのような配列kshは実際には配列ではなく、キーが正の整数に制限された連想配列(または、まばらな配列)に似ています。本当のアレイとシェルの場合は、あなたのようなシェルを見てすることができrcesfishyashzsh(あるいはcsh/ tcshそれらのシェルは非常に多くの問題を抱えているものの、彼らはより良い回避しています)。

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では、unset 'a[3]'との互換性を改善するために実際に空の文字列に設定することに注意してくださいksh

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

in fishbash/に反するBourneのようなシェルではありません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

in esrcBourne風ではなくに基づいて)

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})

kshbash

以下を行うと、通常の配列として配列を使用できます。

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

またことに注意0で開始しない連続かインデックスのリストを作っている可能性があり、各削除または挿入操作の後ksh/ bash配列は0から始まり、1ない(以外の$@(いくつかの点で))。

それは実際に要素を整頓し、それらを順番にインデックス0、1、2 ...に移動します。

また、引用符で囲む必要があることに注意してくださいnumber[i]

unset 'number[i]'

そうでなければ、それは現在のディレクトリでunset numberi呼び出さnumberiれたファイルがあったとして扱われます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.