将两个(管道)shell 命令作为参数传递给 shell 函数

将两个(管道)shell 命令作为参数传递给 shell 函数

我定义了以下 shell 函数:

success() {
  printf "[\033[32mSUCCESS\033[0m]\n"
}

failure() {
  printf "[\033[31mFAILURE\033[0m]\n"
}

try() {
  result=$($* 2>&1)
  if [ $? -ne 0 ]; then
    failure
    echo $result
    exit 1
  fi
  success
}

这使我能够静默执行任何命令,捕获所有输出,并显示SUCCESSFAILURE消息。仅当命令失败时,才会显示命令输出以供调试:

try rm -r $tmp

但我刚刚意识到它仅限于单个命令,并且对于通过管道传输到另一个命令的命令来说会惨败|

try git archive --format=tar HEAD | tar xf - -C $tmp

因为try仅在命令上执行git,然后将 的输出try通过管道传输到tar,而不是 的输出git

是否可以将这两个命令git ... | tar ...作为单个参数传递给try,捕获两者的输出,并检查两者是否gittar返回0

为了实现我的目标,还有其他考虑吗?

答案1

如果您想git … | tar …直接将管道(它是包含两个子命令的单个命令,而不是两个单独的命令)作为参数传递给函数,则需要构建一个包含该命令的字符串,并使用eval函数中的内置函数来将这个字符串作为 shell 命令执行。

注意正确的引用。对于参数,您正在构建一个字符串,它是一个迷你 shell 脚本,使用与封闭脚本相同的变量。特别是,如果变量包含文件名(如此tmp处),则需要传递变量扩展,而不是变量的值,因为文件名不是 shell 片段,所以您需要'…"$tmp"…',而不是"…$tmp…"。评估时,您需要将确切的字符串传递给eval,而不是已经进行扩展的字符串。特别是,$*几乎总是错误的;读为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?

try () {
  result=$(eval "$1" 2>&1)
  if [ $? -ne 0 ]; then
    failure
    echo $result
    exit 1
  fi
  success
}
try 'git archive --format=tar HEAD | tar xf - -C "$tmp"'

另一种方法是将复合命令填充到函数中。再次强调,注意正确引用。用于"$@"将函数的参数计算为简单命令(别名、函数、带参数的内置或外部命令)。

try () {
  result=$(eval "$1" 2>&1)
  if [ $? -ne 0 ]; then
    failure
    echo $result
    exit 1
  fi
  success
}
archive_to_directory () {
  git archive --format=tar HEAD | tar xf - -C "$1"'
}
try archive_to_directory "$tmp"

管道的状态是其右侧的状态;左侧的状态被忽略。在 bash 中(但不在 sh 中),您可以通过以下方式访问管道中所有命令的状态:PIPESTATUS多变的

try () {
  result=$(eval "$1" 2>&1)
  if [ $? -ne 0 ]; then
    failure
    echo $result
    exit 1
  fi
  success
}
archive_to_directory () {
  git archive --format=tar HEAD | tar xf - -C "$1"'
  [[ -n ${PIPESTATUS[*]//[0 ]/} ]]
}
try archive_to_directory "$tmp"

答案2

您必须在命令行上添加一些引用,这是无法避免的

try "git archive --format=tar HEAD | tar xf - -C $tmp"

然后在函数中,由于 shell 元字符(如|)在存储在变量中时并不特殊,因此您需要eval

try() {
  if result=$(eval "$*" 2>&1); then
    success
  else
    failure
    echo $result
    exit 1
  fi
}

我有一种感觉,我还没有完全正确地理解这一点。希望有人能纠正我。

相关内容