eval(動的変数を生成するために使用されます)を宣言に置き換えると、空の変数が生成されるのはなぜですか?

eval(動的変数を生成するために使用されます)を宣言に置き換えると、空の変数が生成されるのはなぜですか?

bash> 5を使用して、変数に指定されたアーキテクチャに基づいて変数に異なる値を割り当てました。これを行うには関数を使用します。これは完璧に動作します。

# arguments:
  variable name to assign,
  value for mac arch,
  value for pi arch

create_variable_for_arch() {
  if [ "$_run_for_arch" = "mac" ]; then
    eval $1=\$2
  else
    eval $1=\$3
  fi
}

しかし、何らかの理由で私のスクリプトが中断されました。

create_variable_for_arch() {
  if [ "$_run_for_arch" = "mac" ]; then
    declare "$1"="$2"
  else
    declare "$1"="$3"
  fi
}

以下は、create_variable_from_arch() の使用方法を示すスニペットです。

declare _moonlight_opt_audio
declare _arch_specific_stream_command

#
while getopts "b:fahdr:s" options; do
  case $options in
    a)
      create_variable_for_arch "_moonlight_opt_audio" \
        "--audio-on-host" "-localaudio"
      ;;
  esac
done

create_variable_for_arch "_moonlight_opt_fps" "--fps 60" "-fps 60"

start_streaming() {
  _arch_specific_options="$_moonlight_opt_resolution $_moonlight_opt_fps $_moonlight_opt_audio $_moonlight_opt_display_type $_moonlight_opt_bitrate"
  create_variable_for_arch "_arch_specific_stream_command" "$_arch_specific_options stream $_target_computer_ip $_moonlight_opt_app_name" "stream $_arch_specific_options -app $_moonlight_opt_app_name $_target_computer_ip"

  moonlight $_arch_specific_stream_command
}

eval() を使用した場合のトレースは次のとおりです。

+ start_streaming
+ _arch_specific_options='--resolution 1920x1080 --fps 60   --bitrate 5000'
+ create_variable_for_arch _arch_specific_stream_command '--resolution 1920x1080 --fps 60   --bitrate 5000 stream 192.168.1.30 StreamMouse' 'stream --resolution 1920x1080 --fps 60   --bitrate 5000 -app StreamMouse 192.168.1.30'
+ '[' mac = mac ']'
+ eval '_arch_specific_stream_command=$2'
++ _arch_specific_stream_command='--resolution 1920x1080 --fps 60   --bitrate 5000 stream 192.168.1.30 StreamMouse'
+ moonlight --resolution 1920x1080 --fps 60 --bitrate 5000 stream 192.168.1.30 StreamMouse
moonlight --resolution 1920x1080 --fps 60 --bitrate 5000 stream 192.168.1.30 StreamMouse

しかし、宣言によると、

    + start_streaming
    + _arch_specific_options=
    + create_variable_for_arch _arch_specific_stream_command ' stream 192.168.1.30 ' 'stream  -app  192.168.1.30'
    + '[' mac = mac ']'
    + declare '_arch_specific_stream_command= stream 192.168.1.30 '
    + echo moonlight
    moonlight

$_arch_特異的_optionsは最終的に価値がありません。どうしたの?私は変数を引用または引用しないいくつかの異なる方法を試しましたが、引用が何を意味するのか実際には理解していません。

ベストアンサー1

declaretypeset他のシェルに似ており、エイリアスとしてbashも知られていますdeclare)は、現在の範囲で変数を宣言します(タイプおよび/または値を設定できます)。

したがって、ここでは関数のローカル変数を宣言しますcreate_variable_for_arch。関数が返されると、変数は消えます。

bashdeclare/には変数を宣言するオプションがtypesetあります。-gグローバル)、しかし、関数呼び出し元の範囲ではなく、最も外側の範囲で変数を宣言し、その型や値を設定するので使用できないので、そこではかなり役に立ちません。mkshスキップするだけzshyashローカライズまたは、静的範囲で ksh93 を使用します。`declare name`と`declare -g`は何をしますか?詳細はこちら)。

したがって、ここではevalnamerefを使用または使用するオプションがあります。

create_variable_for_arch() {
  if [ "$_run_for_arch" = mac ]; then
    eval "$1=\$2"
  else
    eval "$1=\$3"
  fi
}

または、$_run_for_archスクリプト内の定数を想定します。

if [ "$_run_for_arch" = "mac" ]; then
  create_variable_for_arch() { eval "$1=\$2"; }
else
  create_variable_for_arch() { eval "$1=\$3"; }
fi

またはnamerefを使用してください。

create_variable_for_arch() {
  typeset -n _var_name="$1"
  if [ "$_run_for_arch" = mac ]; then
    _var_name=$2
  else
    _var_name=$3
  fi
}

eval通常、セキュリティ上の理由からこれを避けることをお勧めします(正しく)が、eval正しく使用しても安全です。どちらもコードを評価できるため、誤って使用すると安全でdeclareはありません。namerefs

すべて:

f() { eval "$1=\$2"; }
f() { declare "$1=$2"; }
f() { declare -n v="$1"; v=$2; }

rebootこのコマンドは、次のように呼び出されると実行されます。

f 'a[$(reboot)]' value

ランダムなコマンド実行の脆弱性を回避するには、最初の引数が変数名であることを確認することが重要です。

f() { declare $1=$2; }

状況はさらに悪化します。これらのパラメータ拡張は引用されていないため、分割+グローブの対象となります。したがって、内容でさえ、$2次のようにシェルコードで評価できます。

f var 'foo a[$(reboot)]='

おすすめ記事