Bashスクリプトのddスタイルパラメータ

Bashスクリプトのddスタイルパラメータ

ddスタイルのbashスクリプトにパラメータを渡したいです。基本的に私は欲しい

./script a=1 b=43

同じ効果がある

a=1 b=43 ./script

私は次の方法でこれを達成できると思います。

for arg in "$@"; do
   eval "$arg";
done

eval安全な(つまり、"$arg"静的一致(コード実行なし))変数の割り当てを確実にするための良い方法は何ですか?

それとももっと良い方法がありますか? (簡単に保ちたかった)。

答え1

evalなし(および手動エスケープなし)でbashでこれを行うことができます。

for arg in "$@"; do
  if [[ $arg =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; then
    declare +i +a +A "$arg"
  fi
done

編集する:Stéphane Chazelasのコメントに従って、割り当てられた変数が配列または整数変数として宣言されるのを防ぐために、宣言にフラグを追加しました。これにより、多くの場合、引数の値部分をdeclare評価しなくなりますkey=val。 (+aたとえば、設定した変数が配列変数として宣言されているとエラーが発生します。)これらの脆弱性はすべて、この構文を使用して既存の(配列または整数)変数を再割り当てすることに関連しています。シェル変数として知られています。

実際、これは同じevalソリューションに影響を与える注入攻撃クラスの一例にすぎません。既知のパラメータ名のみを許可することは、コマンドラインに表示される変数を盲目的に設定するよりもはるかに優れています。 (PATHたとえば、コマンドラインで設定した場合は、何が起こるのかを考えてみてくださいPS1

私はbash変数を使用するよりも、名前付きパラメータの連想配列を使用することを好みます。これは設定が簡単で安全です。あるいは、実際のbash変数を設定できますが、その名前が有効な引数の連想配列にある場合にのみ可能です。

後者のアプローチの例は次のとおりです。

# Could use this array for default values, too.
declare -A options=([bs]= [if]= [of]=)
for arg in "$@"; do
  # Make sure that it is an assignment.
  # -v is not an option for many bash versions
  if [[ $arg =~ ^[[:alpha:]_][[:alnum:]_]*= &&
        ${options[${arg%%=*}]+ok} == ok ]]; then
    declare "$arg"
    # or, to put it into the options array
    # options[${arg%%=*}]=${arg#*=}
  fi
done

答え2

POSIX 1(/ ...などの特殊変数関連の問題を回避する$<prefix>varのではなく設定):$varIFSPATH

prefix=my_prefix_
for var do
  case $var in
    (*=*)
       case ${var%%=*} in
         "" | *[!abcdefghijiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]*) ;;
         (*) eval "$prefix${var%%=*}="'${var#*=}'
       esac
  esac
done

として呼び出され、myscript x=1 PATH=/tmp/evil %=3 blah '=foo' 1=2次を割り当てます。

my_prefix_x <= 1
my_prefix_PATH <= /tmp/evil
my_prefix_1 <= 2

答え3

ハードコーディングされたプレフィックスでリファクタリングされたlcd047のソリューションDD_OPT_

while [[ $1 =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; do
  eval "DD_OPT_${1%%=*}"='${1#*=}'; shift;
done

フロストスーツリファクタリングのほとんどは賞賛する価値があります。

ソースファイルにグローバル変数として入れました。

DD_OPTS_PARSE=$(cat <<'EOF'
  while [[ $1 =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; do
    eval "DD_OPT_${1%%=*}"='${1#*=}'; shift;
  done
EOF
)

eval "$DD_OPTS_PARSE"すべての魔法を発揮してみてください。

関数のバージョンは次のとおりです。

DD_OPTS_PARSE_LOCAL="${PARSE_AND_REMOVE_DD_OPTS/DD_OPT_/local DD_OPT_}"

使用中:

eval "$DD_OPTS_PARSE_LOCAL"

私は一つ作った買戻契約それに加えて、テストとREADME.mdがあります。その後、私が書いていたGithub API CLIラッパーでこれを使用し、上記のgithubクローンを設定するために同じラッパーを使用しました。買戻契約(起動するのは楽しいです)。

bashスクリプトに引数を安全に渡すのに1行で十分です。楽しんでください。 :)

答え4

私の試み:

#! /usr/bin/env bash
name='^[a-zA-Z][a-zA-Z0-9_]*$'
count=0
for arg in "$@"; do
    case "$arg" in
        *=*)
            key=${arg%%=*}
            val=${arg#*=}

            [[ "$key" =~ $name ]] && { let count++; eval "$key"=\$val; } || break

            # show time
            if [[ "$key" =~ $name ]]; then
                eval "out=\${$key}"
                printf '|%s| <-- |%s|\n' "$key" "$out"
            fi
            ;;
        *)
            break
            ;;
    esac
done
shift $count

# show time again   
printf 'arg: |%s|\n' "$@"

RHSのほぼすべてのゴミを処理することができます。

$ ./assign.sh Foo_Bar33='1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0' '1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0=33'
|Foo_Bar33| <-- |1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0|
arg: |1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0=33|

$ ./assign.sh a=1 b=2 c d=4
|a| <-- |1|
|b| <-- |2|
arg: |c|
arg: |d=4|

関連情報