如何使用Bash将函数的输出赋值给变量?

142
我有一个Bash函数,它会产生一些输出:
function scan {
  echo "output"
}

如何将此输出分配给变量?

例如:VAR=scan(当然这不起作用-它使VAR等于字符串“scan”)


1
相关链接:https://dev59.com/_HA75IYBdhLWcg3wi5or - AlikElzin-kilaka
3个回答

205
VAR=$(scan)

和程序一样,完全相同的方式。


3
我发现当我输入 "echo $VAR" 时,换行符会被去掉。但如果我给 $VAR 加上引号,它就会保留换行符。 - Brent
2
那不是100%正确的。命令替换总是会剥离尾随的换行符。 - TheBonsai
17
这会创建一个子shell;有没有办法在同一shell中完成这个操作? - lmat - Reinstate Monica
2
@lmat-ReinstateMonica,在Bash 4.3及以上版本中,您可以使用所谓的“nameref”来实现这一点。 [此答案](https://dev59.com/ALv9zYgBFxS5KdRj6cXa#39930905)涵盖了一些概念。 - init_js

37

您可以在命令/管道中像使用普通程序一样使用bash函数。这些函数也可用于子shell并且可以通过命令替换进行传递:


VAR=$(scan)

在大多数情况下,直接实现您想要的结果是最简单的方法。我将在下面概述特殊情况。

保留尾随换行符:

命令替换的一个(通常有用的)副作用之一是它将剥离任意数量的尾随换行符。如果希望保留尾随换行符,则可以将一个虚拟字符附加到子Shell的输出,并随后使用参数扩展来去除它。

function scan2 () {
    local nl=$'\x0a';  # that's just \n
    echo "output${nl}${nl}" # 2 in the string + 1 by echo
}

# append a character to the total output.
# and strip it with %% parameter expansion.
VAR=$(scan2; echo "x"); VAR="${VAR%%x}"

echo "${VAR}---"

输出结果(保留3个换行符):

output


---

使用输出参数:避免子shell(并保留换行)

如果函数要实现的是将一个字符串“返回”到变量中,那么在bash v4.3及以上版本中,可以使用所谓的nameref。Nameref允许函数将一个或多个变量输出参数的名称作为参数。您可以将内容分配给nameref变量,就好像您更改了它所“指向/引用”的变量一样。

function scan3() {
    local -n outvar=$1    # -n makes it a nameref.
    local nl=$'\x0a'
    outvar="output${nl}${nl}"  # two total. quotes preserve newlines
}

VAR="some prior value which will get overwritten"

# you pass the name of the variable. VAR will be modified.
scan3 VAR

# newlines are also preserved.
echo "${VAR}==="

输出:

output

===

这个表单有一些优点。特别是,它允许您的函数修改调用者的环境,而无需在全局变量中到处使用。

注意:如果您的函数严重依赖于bash内置功能,则使用namerefs可以大大提高程序的性能,因为它避免了创建一个在之后被丢弃的子shell。这通常更适合经常重复使用的小型函数,例如以echo "$returnstring"结尾的函数。

这很相关。 https://dev59.com/_HA75IYBdhLWcg3wi5or#38997681


0

我认为 init_js 应该使用 declare 而不是 local!

function scan3() {
    declare -n outvar=$1    # -n makes it a nameref.
    local nl=$'\x0a'
    outvar="output${nl}${nl}"  # two total. quotes preserve newlines
}

local 内置命令将接受 declare 内置命令所接受的任何选项。从快速测试来看,在函数作用域中使用 declare -n 也会使变量具有本地作用域。在这里它们似乎是可以互换的。 - init_js

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接