Bash関数パラメータの奇妙な動作

Bash関数パラメータの奇妙な動作

以下のbash機能があります。

lscf() {
  while getopts f:d: opt ; do
    case $opt in
      f) file="$OPTARG" ;;
      d) days="$OPTARG" ;;
    esac
  done

  echo file is $file
  echo days is $days
}

パラメーターを使用してこのコマンドを実行すると、値は出力されません。引数なしで関数を実行し、再度引数を使用して関数を実行した後にのみ正しい値が出力されます。

-bash-4.1$ lscf -d 10 -f file.txt
file is
days is

-bash-4.1$ lscf
file is
days is

-bash-4.1$ lscf -d 10 -f file.txt
file is file.txt
days is 10

私は何を逃したことがありませんか?

ベストアンサー1

あなたの質問に出てきた関数の最初の実行を再現することはできませんが、関数をOPTIND繰り返し呼び出すときに関数のコマンドラインを処理できるように関数を1にリセットする必要があります。

bashマニュアルから:

OPTINDシェルまたはシェルスクリプトが呼び出されるたびに1に初期化されます。オプションにパラメータが必要な場合は、getoptsパラメータを変数に入れますOPTARGシェルはOPTIND 自動的にリセットされません。getopts新しいパラメータセットを使用するには、同じシェル呼び出し間で手動でリセットする必要があります。

~からPOSIX規格:

アプリケーションのOPTIND値が1に設定されている場合は、新しいパラメータセット(現在の場所パラメータまたは新しい引数値)を使用できます。getoptsすべての呼び出しで異なるOPTIND値または値を1以外の値に変更する引数(位置パラメーターまたは引数オペランド)を使用して単一のシェル実行環境内で複数の呼び出しを試みると、未指定の結果が生成されます。

マニュアルでは、bashPOSIX テキストがシェルスクリプトまたはインタラクティブシェルを参照する「単一実行環境」を参照するのと同じ方法で「シェル呼び出し」を参照します。スクリプトまたは対話型シェルから複数回呼び出すとlscf同じ環境になり、各呼び出しの前に1にリセットする必要があります。getoptsOPTIND

だから:

lscf() {
  OPTIND=1

  while getopts f:d: opt ; do
    case $opt in
      f) file="$OPTARG" ;;
      d) days="$OPTARG" ;;
    esac
  done

  echo file is $file
  echo days is $days
}

変数filedays必要な場合いいえ呼び出しシェルの環境に設定されている場合は、ローカル変数でなければなりません。また、参照変数が拡張され、printf変数データの出力にも使用されます。

lscf() {
  local file
  local days

  OPTIND=1

  while getopts f:d: opt ; do
    case $opt in
      f) file="$OPTARG" ;;
      d) days="$OPTARG" ;;
    esac
  done

  printf 'file is %s\n' "$file"
  printf 'days is %s\n' "$days"
}

おすすめ記事