Bash 没有子shell的字符串插值
Bash string interpolation without subshell
我有这样的功能
print_stuff_and_set_vars() {
IMPORTANT_VAL_1=""
IMPORTANT_VAL_2=""
echo -n "some stuff"
echo -n "some more stuff"
echo -n "result"
}
我这样称呼它:
my_main_func() {
print_stuff_and_set_vars
print_stuff_and_set_vars
print_stuff_and_set_vars
echo "IMPORTANT_VAL_1 was $IMPORTANT_VAL_1"
}
相反,我想将所有回显结果保存到一个字符串
my_main_func() {
# doesn't work -- result is empty
result="${print_stuff_and_set_vars}${print_stuff_and_set_vars}${print_stuff_and_set_vars}"
echo "the result length was ${#result}"
echo "$result"
echo "IMPORTANT_VAL_1 was $IMPORTANT_VAL_1"
}
如果我使用 $()
而不是 ${}
来启动子 shell,那么 确实 工作,但是没有设置全局变量。
有没有什么方法可以在不启动子 shell 的情况下将函数的结果保存到字符串中?我知道这个例子中明显的答案是将“结果”保存到全局变量而不是回显它,但在我的实际脚本中这需要大量更改,我想尽可能避免它。
实际上,我只需要知道长度,所以如果有一种方法可以跟踪自函数开始以来打印了多少,那也可以正常工作。如果这也有所不同,我实际上正在使用 zsh
。
使用临时文件很容易做到这一点。示例:
print_stuff_and_set_vars() {
IMPORTANT_VAL_1="x"
IMPORTANT_VAL_2="y"
echo -n "some stuff"
echo -n "some more stuff"
echo -n "result"
}
print_stuff_and_set_vars > /tmp/$$
myVar=$(< /tmp/$$)
echo $myVar
echo $IMPORTANT_VAL_1
echo $IMPORTANT_VAL_2
也可以使用命名管道或文件描述符来实现。
假设函数 print_stuff_and_set_vars
的输出不包含换行符,那么:
mkfifo p # create a named pipe "p"
exec 3<>p # open fd 3 for both reading and writing
rm p # now "p" can be closed
print_stuff_and_set_vars() {
IMPORTANT_VAL_1="foo"
IMPORTANT_VAL_2="bar"
echo -n "some stuff "
echo -n "some more stuff "
echo -n "result "
}
my_main_func() {
print_stuff_and_set_vars 1>&3 # redirect to fd 3
print_stuff_and_set_vars 1>&3 # same as above
print_stuff_and_set_vars 1>&3 # same as above
echo 1>&3 # send newline as an end of input
IFS= read -r -u 3 result # read a line from fd 3
echo "the result length was ${#result}"
echo "$result"
echo "IMPORTANT_VAL_1 was $IMPORTANT_VAL_1"
}
my_main_func
exec 3>&- # close fd 3
输出:
the result length was 102
some stuff some more stuff result some stuff some more stuff result some stuff some more stuff result
IMPORTANT_VAL_1 was foo
我有这样的功能
print_stuff_and_set_vars() {
IMPORTANT_VAL_1=""
IMPORTANT_VAL_2=""
echo -n "some stuff"
echo -n "some more stuff"
echo -n "result"
}
我这样称呼它:
my_main_func() {
print_stuff_and_set_vars
print_stuff_and_set_vars
print_stuff_and_set_vars
echo "IMPORTANT_VAL_1 was $IMPORTANT_VAL_1"
}
相反,我想将所有回显结果保存到一个字符串
my_main_func() {
# doesn't work -- result is empty
result="${print_stuff_and_set_vars}${print_stuff_and_set_vars}${print_stuff_and_set_vars}"
echo "the result length was ${#result}"
echo "$result"
echo "IMPORTANT_VAL_1 was $IMPORTANT_VAL_1"
}
如果我使用 $()
而不是 ${}
来启动子 shell,那么 确实 工作,但是没有设置全局变量。
有没有什么方法可以在不启动子 shell 的情况下将函数的结果保存到字符串中?我知道这个例子中明显的答案是将“结果”保存到全局变量而不是回显它,但在我的实际脚本中这需要大量更改,我想尽可能避免它。
实际上,我只需要知道长度,所以如果有一种方法可以跟踪自函数开始以来打印了多少,那也可以正常工作。如果这也有所不同,我实际上正在使用 zsh
。
使用临时文件很容易做到这一点。示例:
print_stuff_and_set_vars() {
IMPORTANT_VAL_1="x"
IMPORTANT_VAL_2="y"
echo -n "some stuff"
echo -n "some more stuff"
echo -n "result"
}
print_stuff_and_set_vars > /tmp/$$
myVar=$(< /tmp/$$)
echo $myVar
echo $IMPORTANT_VAL_1
echo $IMPORTANT_VAL_2
也可以使用命名管道或文件描述符来实现。
假设函数 print_stuff_and_set_vars
的输出不包含换行符,那么:
mkfifo p # create a named pipe "p"
exec 3<>p # open fd 3 for both reading and writing
rm p # now "p" can be closed
print_stuff_and_set_vars() {
IMPORTANT_VAL_1="foo"
IMPORTANT_VAL_2="bar"
echo -n "some stuff "
echo -n "some more stuff "
echo -n "result "
}
my_main_func() {
print_stuff_and_set_vars 1>&3 # redirect to fd 3
print_stuff_and_set_vars 1>&3 # same as above
print_stuff_and_set_vars 1>&3 # same as above
echo 1>&3 # send newline as an end of input
IFS= read -r -u 3 result # read a line from fd 3
echo "the result length was ${#result}"
echo "$result"
echo "IMPORTANT_VAL_1 was $IMPORTANT_VAL_1"
}
my_main_func
exec 3>&- # close fd 3
输出:
the result length was 102
some stuff some more stuff result some stuff some more stuff result some stuff some more stuff result
IMPORTANT_VAL_1 was foo