Bashで配列の範囲を設定解除する方法

Bashで配列の範囲を設定解除する方法

配列要素の範囲を削除しようとしていますが、失敗します。

私の配列

root@ubuntu:~/work# echo ${a[@]}
cocacola.com airtel.com pepsi.com

0-1配列を印刷すると問題ないようです

root@ubuntu:~/work# echo ${a[@]::2}
cocacola.com airtel.com

今、私は以下を使用してこれらの要素のみを削除しようとしています:

root@ubuntu:~/work# unset a[@]::2
root@ubuntu:~/work# echo ${a[@]}

配列全体を削除します。

何が間違っているのでしょうか?

配列の範囲を削除する他の方法を見つけましたが、上記の方法が機能しないのはなぜでしょうか?

for ((i=0; i<2; i++)); do unset a[$i]; done

編集 私も試してみましたが、運がありませんでした

unset -v 'a[@]::2'

答え1

覚えておくべきことの 1 つは、bashのような実装された配列ksh、つまりキーが正の整数に制限される連想配列であることです (たとえば や のような他の言語とは異なりますperl) zsh

で:

a[123]=foo a[456]=bar a[789]=baz

bash では 3 つの要素を持つ連想配列が得られますが、 ではperl790 個の要素 (zsh では 789 個) を持つ配列が得られます。

kshまたはではbash${a[@]:0:1}キーが 0 以上である、キーによって数値的にソートされた要素のリスト内の配列の最初の要素を返します。したがって、その場合は では${a[123]}なく を返します${a[0]}

unset 'a[123]'

(引用符で囲むことを忘れないでください。そうしないと、現在のディレクトリに a1 または a2 または a3 というファイルがある場合に失敗します) は、配列内の特定のキーを削除するので意味があります。

unset 'a[@]::2'

ただし、あまり意味がありません。 は、または のみbashを理解し、それ以降のものはすべて無視されるため、と は同じことを行います。つまり、配列全体を設定解除します。unset aunset 'a[123]'unset 'a[*/@]'unset 'a[@]::2'unset 'a[@]please'

キーの範囲を設定解除したい場合は、キーをループする必要があります。

配列のキーのリストを取得するには、構文は です"${!a[@]}"。残念ながら、 に範囲を適用してもbashや では機能しないkshため、一時的な配列が必要になります。

keys=("${!a[@]}")
for i in "${keys[@]::2}"; do unset "a[$i]"; done

ここで、他の言語のようにこれらの配列を考慮したい場合は、 を使用したくないはずですunset。たとえば、配列がそもそもスパースではなく、その状態を維持したい場合 (つまり、最初の 2 つの要素を設定解除するのではなく、すべての要素を 2 ずつシフトする場合)、次のようにすることができます。

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

つまり、保持したい要素のリストを配列に再割り当てします。

比較のために、 とzsh

a=({1..20})
unset 'a[12,16]'

は要素 12 から 16 に空の値を設定します。一方、unset 'a[16,20]'は配列を 15 要素に縮小します。

a=({1..20})
a[12,16]=()

(まだzsh) は要素 17 から 20 を 5 位置シフトするので がa[12]含まれます17

答え2

  1. 配列が連続的/非散在的(0..N-1 セットのすべての要素)

    配列の2番目の要素を削除するには

    unset 'a[1]'
    

    2番目、3番目、4番目の要素を削除するには、例えば次のようにします。

    for ((i=1; i<=3; i++)); do unset "a[$i]"; done
    

    1番目と2番目の要素以外をすべて削除するには、例えば次のようにします。

    for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done
    
  2. 一般的な解決策(疎な配列でも機能します):配列の2番目の要素を削除するには、

    unset "a[$(echo ${!a[@]} | cut -d" " -f 2)]"
    

    2番目、3番目、4番目の要素を削除するには、例えば次のようにします。

    for $(echo ${!a[@]} | cut -d" " -f 2-4) ; do unset "a[$i]"; done
    

    1番目と2番目の要素以外をすべて削除するには、例えば次のようにします。

    for $(echo ${!a[@]} | cut -d" " -f 2-) ; do unset "a[$i]"; done
    

関連情報