中間の一部のインデックスでbash配列を移動する方法は?

中間の一部のインデックスでbash配列を移動する方法は?
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.

配列が12行のstdoutに基づいて更新されたように見えますが、13行のstdoutが空であるのはなぜですか?

では、予想される答え「69」を得るにはどうすればよいですか?

答え1

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

配列にはa2から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)

提案通りトビースペートコメントには、5番目の要素(インデックス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")

ご覧のとおり、5番目の要素が削除され、残りのすべての要素の番号が再割り当てされます。

${numbers[@]:0:4}Slices array 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]indexから配列要素を削除しますsubscript。インデックス配列の負の添え字は、上記のように説明されます。パス名拡張による不要な副作用を防ぐために注意を払う必要があります。 unset namename配列はどこにありますか、unset name[subscript]どこにsubscriptありますか? * または @、配列全体を削除します。

答え2

bashinのような配列は、ksh実際の配列ではなく、連想配列(またはいわゆる話す配列)に近いです。まれな配列)。実際の配列を持つシェルの場合rc、、、、、などのesシェルを見ることができます(たとえ/これらのシェルには多くの問題があるので避けるのが最善です)。fishyashzshcshtcsh

存在する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

fish/とは異なり、Bourneのようなシェルではありません):bashzsh

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 es( rcBourne のようなものではない に基づいている)

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

ksh一緒にするbash

これにより、その配列を通常の配列として使用できます。

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

これにより、インデックスリストが連続していないか、各削除または挿入操作の後にゼロから始まらない可能性があります。また、ksh/bash配列は1ではなく0から始まることに注意してください($@(ある意味では除く))。

これは実際に要素を照合し、順番にインデックス0、1、2...に移動します。

また、次の事項を引用する必要がありますnumber[i]

unset 'number[i]'

それ以外の場合は、unset numberi呼び出されている現在のディレクトリにファイルがある場合は効果的に実行されます。numberi

関連情報