空のパラメータをコマンドに渡す方法

空のパラメータをコマンドに渡す方法

だから私はこれを持っています:

export ti_arg='';

if [[ -t 1 ]] ; then
   # allow us to kill container if attached to terminal
   export ti_arg='-ti'
fi

(
  cd "$(dirname "$BASH_SOURCE")"


  docker build <...> '.'


  docker run "$ti_arg" --rm  "test-$commit_id"
)

問題は、$ ti_argが空であるにもかかわらず、シェルがそれを引数として処理して次のような結果を得ることです。

docker: 無効な参照形式

私が考えることができる唯一の解決策は、基本的に同じif / else dockerコマンド(該当する引数を除く)を実行するか、次のようにdockerで使用できる転送引数を見つけることです。

export ti_arg='--noop';

if [[ -t 1 ]] ; then
   # allow us to kill container if attached to terminal
   export ti_arg='-ti'
fi

誰も良い解決策を持っていますか? CLIデザインは常に--noopこのユースケースのフラグを提供するようです。

答え1

それを処理する方法はいくつかあります。基本的なアプローチは、シェルの機能を使用して設定されているパラメータをテストすることです。だからあなたは持つことができます

docker run ${ti_arg:+"$ti_arg"} --rm  "test-$commit_id"

これはti_argが設定されているかどうかをテストし、そうであればそれをに入れます"$ti_arg"

もちろん、起動スクリプトはexport ti_arg=''最高ではありません。これは、パラメータ値が空の文字列であることを明示的に意味します。値が設定されていないと言う方が良いでしょうunset ti_arg。ただし、この場合は問題は解決しません。ただし、値が設定されていない状況をよりよく表現するためにを使用できます${ti_arg+"$ti_arg"}(がないことに注意してください)。:

「$@」の使い方

幸いなことに、昔から人々は

subprog ${1:"$@"}

この問題を解決するには、スクリプトでパラメータ拡張を処理してください。 Bourneのすべての最新実装(シェルなど)では、このバグが修正されているので(二重引用符で)単に言うことができ、"$@"値が設定されていない場合は正しくnullに拡張されます。したがって、名前付き変数を使用する代わりに、次のものを使用できます。

set -- # Clear the $@ array
if [[ -t 1 ]] ; then
    set -- "-ti"
fi
...
docker run "$@" --rm  ....

Cプログラマに関する注意事項

おなじみの人のためにC設定されていない変数と空の文字列に設定されるものの違いは次のとおりです。

  1. char *var = NULL; /* unset case. var is 4 or 8 bytes all of which are 0 */
  2. char *var = strdup(""); /* set to the empty string. var is still 4 or 8 8 bytes, but now contains the address of an item in the heap, which could be as small as 1 byte. The first byte of this heap item will be 0, to indicate the end of string */

答え2

アイテムを配列にプッシュし、配列置換を使用できます。これには、要素のない配列を完全に最適化できるという驚くべき利点があります。以下はユーザーコードの変更部分です。

(
  cd "$(dirname "$BASH_SOURCE")"

  docker build --build-arg commit_id -t "test-$commit_id" .

  set --
  test -n "$ti_arg" && set -- "$ti_arg"

  docker run "$@" --rm  "test-$commit_id"
)

使用する場合は、使用を避け、より簡素化することができbashます。$@

(
  cd "${BASH_SOURCE%/*}"

  docker build --build-arg commit_id -t "test-$commit_id" .

  args=()
  [[ -n "$ti_arg" ]] && args+=("$ti_arg")

  docker run "${args[@]}" --rm "test-$commit_id"
)

どちらのソリューションも、"$ti_arg"意図しないシェルの評価を防ぐために二重引用符を使用します。この特別なケースでは、シェルが補間または評価できるように、最終値を$ti_arg単に引用符で引くこともできますが、一般的な解決策では、変数またはそのコンテキスト(含まれている)が破損する可能性があります。私がもっと好む理由のための予期しない入力上記の複雑で完全な解決策。docker run-tiIFS

docker run $ti_arg --rm "test-$commit_id"

関連情報