如果我有一个这样的函数:
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}