我一直在看别人写的一些脚本(特别是Red Hat),其中许多变量是使用以下符号分配的:
VARIABLE1="${VARIABLE1:-some_val}"
或一些扩展其他变量的方法
VARIABLE2="${VARIABLE2:-`echo $VARIABLE1`}"

使用这种表示法而不是直接声明值(例如VARIABLE1=some_val)有什么意义?

这种表示法是否有好处或可以避免的错误?

:-在这种情况下是否有特定含义?

评论

看看男子扑!搜索块“ Parameter Expansion”(大约28%)。这些分配是例如默认功能:“仅在未设置默认值的情况下使用默认值。”

由于:-设置默认值,如果变量不为null,则:+用于更改值。例如。 v =选项; cmd $ {v:+ with $ v}将运行“带有选项的cmd”。但是,如果$ v为null,它将仅运行“ cmd”。

#1 楼

如果另一个变量为空或未定义,则此技术允许为变量分配值。注意:此“其他变量”可以相同或另一个变量。

摘录

如果您想查看Bash中可用的所有形式的参数扩展的完整列表,那么我强烈建议您在Bash Hacker的Wiki的标题为“参数扩展”的主题中进行研究。

示例

变量不存在

${parameter:-word}
    If parameter is unset or null, the expansion of word is substituted. 
    Otherwise, the value of parameter is substituted.


变量存在

$ echo "$VAR1"

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
default value


通过评估其他变量或在符号的默认值部分内运行命令,可以完成同一件事。

$ VAR1="has value"
$ echo "$VAR1"
has value

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
has value


更多示例

您还可以在${parameter-word}处使用略有不同的表示法。未定义,因此使用默认值VARX=${VARX-<def. value>}

另一个示例

$ VAR2="has another value"
$ echo "$VAR2"
has another value
$ echo "$VAR1"

$

$ VAR1="${VAR1:-$VAR2}"
$ echo "$VAR1"
has another value


使用$VAR1表示法检查和分配

最后,我会提到方便的运算符$VAR2。如果被测变量为空或未定义,这将进行检查并分配一个值。

示例

请注意,现在已设置$VAR3。操作员0只需一次操作即可完成测试和赋值。

$ echo "${VAR1-0}"
has another value
$ echo "${VAR2-0}"
has another value
$ echo "${VAR3-0}"
0


但是,如果该值事先设置,则将其保留。 />
$ VARX="${VAR3-0}"
$ echo "$VARX"
0


便捷的Dandy参考表



参考文献


参数扩展-Bash黑客Wiki
10.2。参数替换
Bash参数扩展


评论


请注意,并非所有这些扩展都以bash记录。 Q中的$ {var:-word}是一个,但不是上面的$ {var-word}。 POSIX文档中有一张漂亮的表格,可能值得将其复制到此答案中-pubs.opengroup.org/onlinepubs/9699919799/utilities/…

– Graeme
2014年4月3日在1:02

@Graeme,有文档记录,您只需要注意在未设置参数的测试中省略冒号结果即可。

–StéphaneChazelas
15/12/22在11:31

如果您实际上想要回显,则使用回显“ $ {FOO:= default}”很棒。但是,如果不这样做,请尝试:内置命令...:$ {FOO:= default}您的$ FOO设置为上述默认值(即,如果尚未设置)。但是在此过程中,没有回音$ FOO。

–fbicknel
17年8月10日在19:50

好的,找到答案了:stackoverflow.com/q/24405606/1172302。使用$ {4:-$ VAR}将起作用。

– Nikos Alexandris
18年1月19日在9:23

+1仅用于详细答案。但事实上,您引用了出色的bash Wiki。还要为您提供示例和表格。地狱,一直到+1才行:)就我而言,我的语法几乎正确,但不太正确-我只是不太在意搜索手册页(不费力,但我不记得它的标题是什么)从今天早上4点起我就一直醒着:()..

–Pryftan
18年2月11日在14:43

#2 楼

@slm已经包含了POSIX文档-非常有用-但它们并没有真正扩展这些参数如何相互影响的组合。这种形式在这里还没有提及:

${var?if unset parent shell dies and this message is output to stderr}


这是我的另一个答案的摘录,我认为它很好地演示了这些工作原理: br />
    sh <<-\CMD
    _input_fn() { set -- "$@" #redundant
            echo ${*?WHERES MY DATA?}
            #echo is not necessary though
            shift #sure hope we have more than  parameter
            : ${*?WHERES MY DATA?} #: do nothing, gracefully
    }
    _input_fn heres some stuff
    _input_fn one #here
    # shell dies - third try doesnt run
    _input_fn you there?
    # END
    CMD
heres some stuff
one
sh: line :5 *: WHERES MY DATA?


来自另一个的示例:

    sh <<-\CMD
    N= #N is NULL
    _test=$N #_test is also NULL and
    v="something you would rather do without"    
    ( #this subshell dies
        echo "v is ${v+set}: and its value is ${v:+not NULL}"
        echo "So this ${_test:-"$_test:="} will equal ${_test:="$v"}"
        ${_test:+${N:?so you test for it with a little nesting}}
        echo "sure wish we could do some other things"
    )
    ( #this subshell does some other things 
        unset v #to ensure it is definitely unset
        echo "But here v is ${v-unset}: ${v:+you certainly wont see this}"
        echo "So this ${_test:-"$_test:="} will equal NULL ${_test:="$v"}"
        ${_test:+${N:?is never substituted}}
        echo "so now we can do some other things" 
    )
    #and even though we set _test and unset v in the subshell
    echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}"
    # END
    CMD
v is set: and its value is not NULL
So this $_test:= will equal something you would rather do without
sh: line 7: N: so you test for it with a little nesting
But here v is unset:
So this $_test:= will equal NULL
so now we can do some other things
_test is still NULL and v is still something you would rather do without


上面的示例利用了POSIX参数的所有4种形式替换及其各种:colon nullnot null测试。在上面的链接中有更多信息,这里再次是。

人们通常不会考虑的关于${parameter:+expansion}的另一件事是,它在本文档中非常有用。这是另一个答案的摘录:

TOP

这里您将设置一些默认值,并准备在调用时打印它们。

#!/bin/sh
    _top_of_script_pr() ( 
        IFS="$nl" ; set -f #only split at newlines and don't expand paths
        printf %s\n ${strings}
    ) 3<<-TEMPLATES
        ${nl=
}
        ${PLACE:="your mother's house"}
        ${EVENT:="the unspeakable."}
        ${ACTION:="heroin"}
        ${RESULT:="succeed."}
        ${strings:="
            I went to ${PLACE} and saw ${EVENT}
            If you do ${ACTION} you will ${RESULT}
        "}
    #END
    TEMPLATES


MIDDLE

在这里,您可以定义其他函数以根据其结果调用打印函数...

    EVENT="Disney on Ice."
    _more_important_function() { #...some logic...
        [ $((1+one)) -ne 2 ] && ACTION="remedial mathematics"
            _top_of_script_pr
    }
    _less_important_function() { #...more logic...
        one=2
        : "${ACTION:="calligraphy"}"
        _top_of_script_pr
    }


底部

现在已经完成所有设置,因此这里是执行并提取结果的地方。

    _less_important_function
    : "${PLACE:="the cemetery"}" 
    _more_important_function
    : "${RESULT:="regret it."}" 
    _less_important_function    


结果

我马上解释一下原因,但是运行上面的代码会产生以下结果:


_less_important_function()'s第一次运行:


我去了你母亲的家,在冰上看到迪斯尼。

如果你做书法,你会成功的。


然后_more_important_function():


我去了公墓,在冰上看了迪斯尼。

如果你做补习数学,你将会成功。


/> _less_important_function()


我去了到墓地并在冰上看到迪斯尼。

如果进行补习数学,您会后悔的。




工作原理:

此处的主要功能是conditional ${parameter} expansion.的概念。仅可以使用以下形式将变量设置为未设置或为null的值:



${var_name:= desired_value}



如果只希望设置一个未设置的变量,则可以忽略:colon,而空值将保持不变。

在范围内:

您可能会注意到,在上面的示例中,即使已调用$PLACE,但通过$RESULT进行设置时,parameter expansion_top_of_script_pr()也会发生变化,大概是在运行时对其进行了设置。起作用的原因是_top_of_script_pr()( subshelled )函数-我将其封装在parens中,而不是其他函数中使用的{ curly braces }。因为它是在子外壳中调用的,所以它设置的每个变量都是locally scoped,并在返回其父外壳时这些值消失了。

但是当_more_important_function()设置$ACTION时,它是globally scoped,因此会影响_less_important_function()'s$ACTION的第二次求值因为_less_important_function()仅通过$ACTION设置了${parameter:=expansion}.

评论


很高兴看到速记默认值在Bourne Shell中有效

– Sridhar Sarnobat
18年3月29日在4:39

#3 楼

个人经验。

我有时在脚本中使用这种格式来临时覆盖值,例如如果我有:

$ cat script.sh
SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING"; 


我可以运行:

$ env SOMETHING="something other than the default value" ./script.sh` 


而不必更改原始默认值代表SOMETHING