如何将命令的输出分配给变量而不在子 shell 中运行该命令?

如何将命令的输出分配给变量而不在子 shell 中运行该命令?

如果我有一个这样的函数:

TEST()
{
    if [[ "$1" == "hi" ]]
    then
        exit 1
    fi

    echo "Some text"
}

如果我在当前 shell 中运行该函数:

TEST "hi"

一切都按预期进行。函数中的 if 语句将为 true,整个脚本将退出。另一方面,如果我这样做:

FUNCTION_OUTPUT=$(TEST "hi")

这样我就可以从变量中的函数捕获标准输出,函数内的 if 语句仍然为 true,“exit 1”仍然会触发,但由于我们在子 shell 中运行,脚本将继续运行。

有没有办法在当前 shell 中运行它,以便我的函数中的“exit 1”行实际上退出整个脚本,而不是使用 VAR_NAME=$() 在子 shell 中运行某些内容并将其分配给变量?

答案1

变量赋值只是一个简单命令,所以你可以使用如果条件检查函数是否成功或失败:

if ! FUNCTION_OUTPUT=$(TEST hi); then
  echo Function return non-zero status
  exit 1
fi

# This line never printed
printf '%s\n' "$FUNCTION_OUTPUT"

如果函数成功,您将获得FUNCTION_OUTPUT包含函数结果的变量:

if ! FUNCTION_OUTPUT=$(TEST hii); then
  echo Function return non-zero status
  exit 1
fi

# Output content of FUNCTION_OUTPUT
printf '%s\n' "$FUNCTION_OUTPUT"

答案2

将命令重定向到文件并使用内置命令将文件读入变量,例如使用mapfile.

答案3

有很多方法可以退出脚本。

VAR=$(FUNCTION) || kill -"$(($?&127))" 0

...可能是一种方式。无论返回的是什么,它都应该传递到父 shell 的进程组FUNCTION。它并没有真正充实,但如果这就是您所要求的,您可以轻松地从命令替换中获得返回。另外,如果您需要有关在当前 shell 函数中分配变量的建议,您可以这样做:

fn(){ var=x; }; fn; echo "$var"

x

如果它必须是某个命令的输出,那么您正在谈论分层评估。您确实需要信任该输出,否则您需要捕获整个流,在这种情况下,您最好确定何时会收到它。这些事情通常是通过管道来完成的 - 这就是命令替换的工作方式 - 当然,还有子 shell。正如 shell 所做的那样,您必须read按照其他地方的建议输入数据。

我喜欢使用自己的小管道 - 我一次向管道的缓冲区写入一点,并在准备好时再次读入。

fn(){ echo hey; read hey; } <> <(:) >&0
fn; echo "$hey"

hey

...我想我应该提到,如果你遵循最后一个例子,你应该特别小心不是来填充缓冲区。一次只写一点,并尽快阅读。几乎在任何系统上,您都可以依靠 512 字节的基线缓冲区(虽然不多),但它们通常更大。

如果您不小心,那么,作为该管道两端的所有者,您的 shell 在死​​锁时将不会从任何其他进程收到任何受挫的退出信号,并且它将永远卡住。我从来不会将任何非内置命令的输出指向这些文件描述符之一,除非我已经分叉了一个读取器进程来根据需要排空管道。

它使得相同的进程消息传递变得困难 - 您必须以完美的同步性精心管理它,并同时跟踪任务的所有单独线程。这就是 shell 分叉的原因。

答案4

我用:

tmp_fifo=$(mktemp)
mkfifo ${tmp_fifo}
exec 5<>${tmp_fifo}

assign() {
  local var=$1;
  shift
  "$@" >&5
  read ${var} <&5
}

assign myVar echo hola
echo $myVar

rm -f ${tmp_fifo}

相关内容