Bash、Caseステートメントを使用して、単語が配列にあることを確認してください。

Bash、Caseステートメントを使用して、単語が配列にあることを確認してください。

限定された定義済みリストの単語をパラメーターとして受け入れる必要があるスクリプトを作成しています。またぜひ行ってください。completeとの間の重複を避けるために、リストを変数に保存しますcase。だから私はこれを書き、完成は機能しますが、caseドアは機能しません。なぜ?ケースステートメントパラメータを作成するために変数を使用することはできませんか?

declare -ar choices=('foo' 'bar' 'baz')
function do_work {
  case "$1" in 
    "${choices[*]}")
      echo 'yes!'
      ;;
    *)
      echo 'no!'
  esac
}
complete -W "${choices[*]}" do_work

ベストアンサー1

のリストは区切りリストcomplete -W listとして解釈され、完成型が考慮されます。$IFS$IFS

したがって、次のような場合:

complete -W 'a b,c d' do_work

do_workaスペースが含まれている場合とb,cスペースが含まれている場合と含まれていない場合に完成機能が提供されます。d$IFSa bc d$IFS,

だからほとんど設計上壊れました。また、任意の文字列を完成として提供することもできません。

これらの制限を適用するための最善の方法は変更されないと$IFS仮定し(したがって、スペース、タブ、および改行が常に含まれるため、完成語に文字を使用できない)、次のことを実行することです。

choices='foo bar baz'
do_work() {
  case "$1" in
    (*' '*) echo 'no!';;
    (*)
      case " $choices " in 
        (*" $1 "*) echo 'yes!';;
        (*) echo 'no!';;
      esac;;
  esac
}
complete -W "$choices" do_work

readonly IFS変更しないように追加できますが、特に親範囲で読み取り専用として宣言されたローカル変数を宣言することを許可しないことを$IFS考慮すると、問題が発生する可能性があります。したがって、これを実行する関数でも破壊されます。bashlocal IFS=,

配列要素に文字列があるかどうかを確認する方法に関するより一般的な質問についてはbash(zshとは異なり)演算子はありませんが、ループを使用して簡単に実装できます。

amongst() {
  local string needle="$1"
  shift
  for string do
    [[ $needle = "$string" ]] && return
  done
  false
}

それから:

do_work {
  if amongst "$1" "${choices[@]}"; then
    echo 'yes!'
  else
    echo 'no!'
  fi
}

文字列を見つけるのに適した構造は、ハッシュテーブルまたは連想配列を使用することです。

typeset -A choices=( [foo]=1 [bar]=1 [baz]=1 )
do_work() {
  if [[ -n ${choices[+$1]} ]]; then
    echo 'yes!'
  else
    echo 'no!'
  fi
}
complete -W "${!choices[*]}" do_work

これは"${!choices[*]}"連想配列のキーを$IFSその点の最初の文字に関連付けます(設定されていますが空の場合は区切り文字は使用されません)。

Bashアソシエーション配列は空のキーを持つことができないため、空の文字列はオプションの1つにすることはできませんが、とにかくサポートされていませcomplete -Wん。許容できる値のうち

おすすめ記事