如何在函数内扩展 bash 函数参数/修复 shellcheck SC2294

how to expand bash function parameters inside function / fix shellcheck SC2294

假设一个函数在另一个目录中运行命令:

sub() {
  cd subdirectory
  eval "$@" || exit
}

我希望能够使用在子目录内扩展的参数调用此函数,例如sub ls '$(basename $(pwd))'

但是,由于上面定义的函数,它没有通过shellcheck:

^-- SC2294 (warning): eval negates the benefit of arrays. Drop eval to preserve whitespace/symbols (or eval as string).

显然,如果我删除 eval,则参数不会展开,如果我也删除引号,则参数会在当前目录中展开。这不是我想要的。

我知道 shellcheck 的 wiki 中有一些建议,但我不知道如何使它们起作用。

在这种情况下是否可以正确使用 eval —— 没有 SC2294 中描述的缺点 —— 还是我需要忽略这条规则?

使用 eval "$*" 而不是 eval "$@"。这将具有完全相同的效果(假设 IFS 具有其默认值)和 Shellcheck is happy with it. See Accessing bash command line args $@ vs $* 对于 $@$*(引用和未引用)的详细信息。

通常不鼓励使用 eval 是有道理的。参见 Why should eval be avoided in Bash, and what should I use instead?。不过有时也没有更好的选择。

... Drop eval ...

所以放弃吧。

sub() {
  cd subdirectory
  "$@" || exit

  # I would do:
  if ! "$@"; then
     exit
  fi
}

sub sh -c 'ls "$(basename "$(pwd)")"'

invoke this function with parameters that are expanded inside the subdirectory

使用eval是邪恶的。考虑一种不同的方法 - 使用将要执行的代码定义一个函数。

todo() {
   # properly escaped script
   ls "$(basename "$(pwd)")"
}
sub todo

而且,总的来说,如果这是为了交互式使用,并且您知道自己在做什么以及 eval 的问题,就不要管它并消除警告。例如,watch 参数是 运行 via sh,比如 watch 'echo $(date)'.

sub() {
    cd subdirectory
    sh -c "$*"
}