如何将空参数传递给命令

Ale*_*lls 1 bash zsh shell-script arguments docker

所以我有这个:

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"
)
Run Code Online (Sandbox Code Playgroud)

问题是,即使 $ti_arg 为空,shell 仍然将其视为参数,我得到:

docker:参考格式无效

我能想到的唯一解决方案是 if/else 运行基本相同的 docker 命令(除了那个 arg),或者找到一些可以与 docker 一起使用的传递参数,如下所示:

export ti_arg='--noop';

if [[ -t 1 ]] ; then
   # allow us to kill container if attached to terminal
   export ti_arg='-ti'
fi
Run Code Online (Sandbox Code Playgroud)

有人有好的解决方案吗?我想 CLI 设计总是会--noop为这个用例提供一个标志......现在去更新你自己的所有 CLI 工具

ica*_*rus 5

有多种方法可以处理它。基本方法是使用 shell 的功能来测试正在设置的参数。所以你可以有

docker run ${ti_arg:+"$ti_arg"} --rm  "test-$commit_id"
Run Code Online (Sandbox Code Playgroud)

这会测试 ti_arg 是否已设置,如果设置了,则将其放入"$ti_arg".

当然,启动脚本export ti_arg=''并不是最好的,这明确表示参数的值为空字符串。使用unset ti_arg说该值未设置会更好,尽管在这种情况下它不能解决问题。但是,它允许您使用${ti_arg+"$ti_arg"}(注意缺少:)来更好地表示您没有设置值的情况。

使用“$@”的技巧

值得庆幸的是,在很久以前,人们会使用

subprog ${1:"$@"}
Run Code Online (Sandbox Code Playgroud)

在他们的脚本中处理参数的扩展来解决这个问题。Bourne 的所有现代实现(如 shell)都修复了此错误,因此您可以直接说"$@"(用双引号),如果没有设置值,它会正确扩展为空。因此,您可以使用而不是使用命名变量

set -- # Clear the $@ array
if [[ -t 1 ]] ; then
    set -- "-ti"
fi
...
docker run "$@" --rm  ....
Run Code Online (Sandbox Code Playgroud)

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 */