bash関数に渡さずに$ @を引用する方法は?

bash関数に渡さずに$ @を引用する方法は?

$@私がやっているように渡さずに他の関数や他のスクリプトファイルで参照する方法を知りたいですgetopts。とても感謝しています!

#前の質問: bash getoptsはどのパラメータが呼び出されるのかをどうやって知ることができますか?

A() {
  B 
} 

B() {

  # how to reference the $@ of A here ?
  # which will be 1 2 3 4


}

A 1 2 3 4

答え1

何らかの方法で位置パラメータを指定しないと、Aこれはできません。B以下を介して渡すことができます。

A() {
  B "$@"
}
B() {
  [ "$#" -eq 0 ] || printf '<%s>\n' "$@"
}

または配列に保存します。

A() {
  A_args=( "$@" )
  B
}
B() {
  [ "${#A_args[@]}" -eq 0 ] || printf '<%s>\n' "${A_args[@]}"
}

Bashは、ash / ksh88 / zsh(ksh93またはzshの変数ではない)などのprivateローカル変数の範囲を動的に指定するため、そのA_args変数localをに設定することも、A呼び出された関数で引き続き使用できますA

bashあなたにアクセス権を与える変わりやすい上位範囲であっても影の下unsetローカル変数は組み込み関数(場合によっては設定解除されず、代わりに親範囲の変数を表示します)として現在のバグを使用して現在の範囲で使用されますが、この方法で親範囲から取得することはできません。 //とは対照的に、bashでは位置パラメータを配列変数にマップできません。なぜなら、bash配列デザインは、配列が実際には配列ではなくzshKornシェルに基づいているからです。rcfish

一部のコードが関数の位置パラメータ、ローカルオプション、またはshift関数内でアクセスまたは変更できるようにするには、そのコードをその関数の範囲内で実行する必要があります。別の機能。setreturn

エイリアスを使用することも、使用しない場合もあります(Cプリプロセッサマクロに対応するシェルですが、引数を受け入れることはできません)eval

しかし、注意してください:

  • Bashシェルでは、POSIXモードではない場合、エイリアス拡張はデフォルトで無効になっているためshopt -s expand_aliases
  • エイリアスが存在する必要があります。今後関数のコードを読み、関数コード内で拡張します。

だからあなたはこれを行うことができます:

[ -z "$BASH_VERSION" ] || shopt -s expand_aliases # work around for bash
alias B='{
  [ "$#" -eq 0 || printf "<%s>\n" "$@"
  shift
}'
A() {
  echo "$#"
  B
  echo "$#"
}
A a b c

または:

B='
  [ "$#" -eq 0 || printf "<%s>\n" "$@"
  shift
'
A() {
  echo "$#"
  eval "$B"
  echo "$#"
}
A a b c

答え2

実際にbashでextdebugこのオプションが有効になっている場合(通常はデバッガの場合)、呼び出しスタック内のすべての関数の位置引数のリストは、各レベルの引数の数$BASH_ARGV(逆順ではありますが)を含む特別な配列で使用できます。$BASH_ARGC

しかし、注意してください:

  • これは読み取り専用です(値を変更しようとしても効果はありません)。
  • extdebugは最初から(最初の関数が呼び出される前に)設定する必要がありますが、bash -O extdebugデバッガを呼び出すため、bashコマンドライン()では設定できません。
  • このオプションを有効にすると、追加の効果についてはドキュメントを確認してください。
shopt -s extdebug
shopt -u xpg_echo
A() {
  B x y
}

reverse_helper() { caller_args=( "${BASH_ARGV[@]:0:BASH_ARGC}" ); }

B() {
  local -a caller_args
  local IFS=,
  reverse_helper "${BASH_ARGV[@]:BASH_ARGC[0]:BASH_ARGC[1]}"
  echo "my args: $*"
  echo "my caller args: ${caller_args[*]}"
}

A a b c

これは作る:

my args: x,y
my caller args: a,b,c

答え3

コメントに基づいて、OPは関数内や関数などの組み込み関数の動作を模倣する方法を尋ねましたshiftgetopts実際にいくつかのトリックを使用するとこれを達成できますが、本番で使用するのが良いアイデアであるかどうかはわかりません。

A() {
  B
} 

B() {
  trap 'shift;trap debug' debug
}

A 1 2 3 4

trap関数Bの最後のコマンドでなければなりません。

戻った後に元のデバッグトラップを維持するには、次のようにします。

A() {
  B
} 

B() {
  local olddebug="$(trap -p debug)"
  trap "shift;trap debug;$olddebug" debug
}

A 1 2 3 4

エイリアスとは異なり、関数は定義前に他の関数で参照でき、再帰的に呼び出すことができ、上書きして同じ関数から新しいバージョンで呼び出すことができます。エイリアスを含むスクリプトファイル内のすべてのエントリを1つの大きな関数にラップし、その関数を呼び出すとエイリアスは失敗しますが、本番環境ではほとんど使用されません。

関連情報