アレイのテストシェルのサポート

アレイのテストシェルのサポート

Bourneに似たデフォルトのシェルを介してコマンドラインで配列サポートをテストするきちんとした方法はありますか?

これは常に可能です。

$ arr=(0 1 2 3);if [ "${arr[2]}" != 2 ];then echo "No array support";fi

または、$SHELLシェルのバージョンをテストしてください。

$ eval $(echo "$SHELL --version") | grep version

次に、マンページにアクセスできるとし、マンページを読んでください。 (執筆時点でも、/bin/bashすべてのBourne様シェルは--versionkshが中断したときに長いオプションを認識すると仮定します。例えば.)

私は無人でマージできる簡単なテストを探しています。使用法スクリプトの冒頭では、前のセクションを呼び出すこともできます。

答え1

Bourneのようなシェル(、、、またはcshサポートtcsh配列などの他の多くのシェルrc)に制限したいのですが、Bourneのようなシェルとも互換性のあるスクリプトを書くのはまったく異なるインタプリタなので、互換性がないので、難しく、しばしば無意味であるとします。 。言語)、実装間に大きな違いがあることに注意してください。esfish

配列をサポートするBourneに似たシェル(サポートが追加された順序で)は次のとおりです。

  • ksh88(元のkshの最後の進化であるksh88は、最初の配列実装であり、ほとんどkshの伝統的な商用Unicesにまだ存在し、その基盤でもありますsh。)

    • 配列は1次元です。
    • 配列がorで始まらないと保証できない場合は、配列をset -A array foo barorと定義してください。set -A array -- "$var" ...$var-+
    • 配列インデックスはから始まります0
    • 個々の配列要素はで指定されますa[1]=value
    • 配列がまれです。これは設定されていないa[5]=foo場合でも機能し、設定されていません。a[0,1,2,3,4]
    • ${a[5]}インデックス5の要素にアクセスします(配列がリーンな場合は必ずしも6番目の要素である必要はありません)。任意の算術式があります5
    • 配列サイズと添字は制限されています(最大4096個)。
    • ${#a[@]}配列の指定された要素数です(指定された最大インデックスではありません)。
    • 割り当てられた添え字のリストを知る方法はありません(4096要素の個々のテストを使用する以外[[ -n "${a[i]+set}" ]])。
    • $a同じです${a[0]}。つまり、配列は追加の値を提供し、任意の方法でスカラー変数を拡張します。
  • pdkshkshそして派生物(いくつかのBSD、時には複数のBSDの基盤であり、shksh93ソースコードがリリースされるまで唯一のオープンソースksh実装でした):

    主に好きksh88ですが、注意してください:

    • 一部の以前の実装ではこれをサポートしていませんset -A array -- foo bar--ここでは必要ありません)。
    • ${#a[@]}割り当てられた最大のインデックスに1を加えたインデックス。 (a[1000]=1; echo "${#a[@]}"配列に要素が1つしかない場合でも、1001が出力されます。
    • 最新バージョンでは、配列サイズは制限されなくなりました(整数サイズを除く)。
    • の最新バージョンには、割り当てられたインデックスのリストを取得するためmkshにインスピレーションを受けた追加の演算子、または割り当てbashlaなどの演算子ksh93があります。zsha=(x y)a+=(z)${!a[@]}
  • zsh。アレイは一般的に設計が良く、zshアレイを最大限に活用します。ご覧のとおりkshcsh1991年にリリースされたzsh 2.0、デザインインスピレーションはkshではなくtcshから来ます。これはksh配列といくつかの類似点を共有しますが、重要な違いもあります。

    • kshインデックスは、Bourne配列(位置パラメータ$ @、zsh$argv配列としても公開されています)と配列とcsh一致して0ではなく1から始まります(シミュレーションを除く)。
    • 一般/スカラー変数とは異なるタイプです。通常、予想されるように、演算子は異なる方法で適用されます。$a配列とは異なり、配列の空${a[0]}でない要素に展開されます("${a[@]}"inなどのすべての要素についてksh)。
    • まれな配列ではなく、通常の配列です。a[5]=1有効であるが割り当てられていない場合、1〜4のすべての要素は空の文字列として割り当てられます。したがって、${#a[@]}(kshのインデックス0の要素と同じサイズ${#a})は配列内の要素の数です。そして指定された最大インデックスです。
    • 連想配列をサポートします。
    • 配列操作のための多数の演算子がサポートされており、ここにリストするには多すぎます。
    • a=(x y)で定義された配列set -A a x yとの互換性にも使用可能ですkshが、kshエミュレーションを除いてはサポートされていません(zshエミュレーションでは必要ありません)set -A a -- x y--
  • ksh93。 (最新バージョンはここで説明されています)。ksh93原作者が書き直したことは長い間考慮されてきました。ksh実験的FOSSとしてリリースされて以来、ますます多くのシステムで見つけることができます。たとえば、これは(POSIXシェルがまだベースになっている/bin/shBourneシェルを置き換える)とです。その配列はksh88の配列を拡張して改善します。/usr/xpg4/bin/shksh88kshSolaris 11

    • a=(x y)配列を定義するために使用できますが、複合変数()a=(...)を定義するためにも使用できるので、あいまいで、配列ではなく複合変数を宣言します。a=(foo=bar bar=baz)a=()
    • 配列は多次元であり(a=((0 1) (0 2)))、配列要素は複合変数でもあります(a=((a b) (c=d d=f)); echo "${a[1].c}")。
    • a=([2]=foo [5]=bar)スパース配列は構文を使用して一度定義できます。
    • 最大配列インデックスが4,194,303に増加しました。
    • 同じ程度ではありませんが、zsh配列で動作する多数の演算子もサポートします。
    • "${!a[@]}"配列インデックスのリストを取得します。
    • 連想配列は別のタイプとしてもサポートされます。
  • bashbashGNUプロジェクトのシェルです。sh最新バージョンのOS / Xおよび一部のGNU / Linuxディストリビューションで使用されています。bash配列は主におよびksh88の一部の機能を使用して配列をシミュレートします。ksh93zsh

    • a=(x y)サポートされます。set -A a x y いいえサポートされます。a=()空の配列を作成します(複合変数はありませんbash)。
    • "${!a[@]}"インデックスのリストを取得します。
    • a=([foo]=bar)文法はもちろん、ksh93その他の文法もサポートされていますzsh
    • 最新bashバージョンでは、連想配列を別の型としてもサポートしています。
  • yash。これは比較的新しい、きれいなマルチバイト認識POSIX sh実装です。広く使われていません。その配列は、次のような別のきれいなAPIです。zsh

    • 配列が稀ではありません。
    • 配列インデックスは1から始まります。
    • 次のように定義(および宣言)されます。a=(var value)
    • array組み込み要素を使用した挿入、削除、修正
    • array -s a 5 value5番目の要素を事前に割り当てないと、変更は失敗します。
    • 配列内の要素の数は、${a[#]}リスト${#a[@]}内の要素のサイズです。
    • 配列は別々の型です。a=("$a")要素を追加または変更する前に、スカラー変数を配列として再定義する必要があります。
    • "$array"そのまま配列内のすべての要素に拡張するので、他のシェルよりも使いやすくなります(配列の要素を引数として使用して呼び出されるksh / bash / zshと比較する;オフですが空の要素を削除cmd "$array"します)。 。cmdcmd "${array[@]}"zshcmd $array
    • として呼び出すと、配列はサポートされませんsh

これにより、配列サポートの検出が表示され、次のことができます。

if (unset a; set -A a a; eval "a=(a b)"; eval '[ -n "${a[1]}" ]'
   ) > /dev/null 2>&1
then
  array_supported=true
else
  array_supported=false
fi

この配列を使用するには不十分です。配列を全体要素と個々の要素として割り当てるには、ラッパーコマンドを定義し、スパース配列を作成しないようにする必要があります。

良い

unset a
array_elements() { eval "REPLY=\"\${#$1[@]}\""; }
if (set -A a -- a) 2> /dev/null; then
  set -A a -- a b
  case ${a[0]}${a[1]} in
    --) set_array() { eval "shift; set -A $1"' "$@"'; }
        set_array_element() { eval "$1[1+(\$2)]=\$3"; }
        first_indice=0;;
     a) set_array() { eval "shift; set -A $1"' -- "$@"'; }
        set_array_element() { eval "$1[1+(\$2)]=\$3"; }
        first_indice=1;;
   --a) set_array() { eval "shift; set -A $1"' "$@"'; }
        set_array_element() { eval "$1[\$2]=\$3"; }
        first_indice=0;;
    ab) set_array() { eval "shift; set -A $1"' -- "$@"'; }
        set_array_element() { eval "$1[\$2]=\$3"; }
        first_indice=0;;
  esac
elif (eval 'a[5]=x') 2> /dev/null; then
  set_array() { eval "shift; $1=("'"$@")'; }
  set_array_element() { eval "$1[\$2]=\$3"; }
  first_indice=0
elif (eval 'a=(x) && array -s a 1 y && [ "${a[1]}" = y ]') 2> /dev/null; then
  set_array() { eval "shift; $1=("'"$@")'; }
  set_array_element() {
    eval "
      $1=(\${$1+\"\${$1[@]}"'"})
      while [ "$(($2))" -ge  "${'"$1"'[#]}" ]; do
        array -i "$1" "$2" ""
      done'
    array -s -- "$1" "$((1+$2))" "$3"
   }
  array_elements() { eval "REPLY=\${$1[#]}"; }
  first_indice=1
else
  echo >&2 "Array not supported"
fi

"${a[$first_indice+n]}"その後、リスト全体を使用して配列要素にアクセスし、"${a[@]}"ラッパー関数(array_elements、、、)を使用して配列要素の数(in )をset_array取得したり、配列を完全に設定したり、単一の要素を割り当てたりできます。set_array_element$REPLY

おそらく努力する価値はないでしょう。perlBourne / POSIXシェル配列を使用または制限します"$@"

ユーザーの対話型シェルが内部で配列を使用する関数を定義するためにいくつかのファイルをインポートすることが目的であれば、ここで役に立つかもしれないいくつかの追加の説明があります。

(関数または匿名関数で)ローカル範囲配列のzshように動作するように配列を設定できます。ksh

myfunction() {
  [ -z "$ZSH_VERSION" ] || setopt localoption ksharrays
  # use arrays of indice 0 in this function
}

次の方法でシミュレーションすることもできますkshksh配列や他の多くの領域との互換性の向上)。

myfunction() {
  [ -z "$ZSH_VERSION" ] || emulate -L ksh
  # ksh code more likely to work here
}

これを念頭に置いて、および以前の派生項目のサポートを中止することを意図しており、スパースyash配列を作成しようとしない限り、以下を一貫して使用できます。ksh88pdksh

  • a[0]=foo
  • a=(foo bar)(しかしa=()
  • "${a[#]}"、、、"${a[@]}""${a[0]}"

ある機能では、ユーザーは通常emulate -L kshzshzshの方法で配列を使用します。

答え2

以下を使用して配列構文を試すことができますeval

is_array_support() (
  eval 'a=(1)'
) >/dev/null 2>&1

if is_array_support; then
  echo support
else
  echo not
fi

関連情報