在脚本中使用“${a:-b}”进行变量赋值

Jus*_*son 593 scripting bash shell-script variable

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

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

这种表示法是否有好处或可以防止可能出现的错误?

是否:-有特定的含义在这方面?

slm*_*slm 974

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

摘抄

${parameter:-word}
    If parameter is unset or null, the expansion of word is substituted. 
    Otherwise, the value of parameter is substituted.
Run Code Online (Sandbox Code Playgroud)

注意:此表格也有效,${parameter-word}。如果您想查看 Bash 中可用的所有参数扩展形式的完整列表,那么我强烈建议您查看 Bash Hacker wiki 中标题为“参数扩展”的主题。

例子

变量不存在
$ echo "$VAR1"

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
default value
Run Code Online (Sandbox Code Playgroud) 变量存在
$ VAR1="has value"
$ echo "$VAR1"
has value

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
has value
Run Code Online (Sandbox Code Playgroud)

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

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

$

$ VAR1="${VAR1:-$VAR2}"
$ echo "$VAR1"
has another value
Run Code Online (Sandbox Code Playgroud)

更多例子

您也可以使用稍微不同的表示法,它只是VARX=${VARX-<def. value>}.

$ echo "${VAR1-0}"
has another value
$ echo "${VAR2-0}"
has another value
$ echo "${VAR3-0}"
0
Run Code Online (Sandbox Code Playgroud)

在上面$VAR1&$VAR2中已经用字符串“has another value”定义了但$VAR3未定义,所以使用默认值,0.

另一个例子

$ VARX="${VAR3-0}"
$ echo "$VARX"
0
Run Code Online (Sandbox Code Playgroud)

使用:=符号检查和分配

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

例子

请注意,$VAR1现在已设置。操作员:=在一次操作中完成了测试和分配。

$ unset VAR1
$ echo "$VAR1"

$ echo "${VAR1:=default}"
default
$ echo "$VAR1"
default
Run Code Online (Sandbox Code Playgroud)

但是,如果该值是预先设置的,那么它就被保留了下来。

$ VAR1="some value"
$ echo "${VAR1:=default}"
some value
$ echo "$VAR1"
some value
Run Code Online (Sandbox Code Playgroud)

方便的花花公子参考表

    表的ss

参考

  • 如果你真的想要 `echo`,那么使用 `echo "${FOO:=default}"` 是很棒的。但是如果你不这样做,那么试试`:` 内置的... `: ${FOO:=default}` 你的 `$FOO` 被设置为 `default`,如上(即,如果尚未设置) . 但是在这个过程中没有回显`$FOO`。 (13认同)
  • 请注意,并非所有这些扩展都记录在 `bash` 中。Q 中的 `${var:-word}` 是,但不是上面的 `${var-word}`。POSIX 文档有一个不错的表格,但可能值得将其复制到此答案中 - http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02 (10认同)
  • @Graeme,它已记录在案,您只需要注意 _Omitting 冒号结果仅针对未设置的参数进行测试。_ (7认同)
  • 好的,找到了答案:/sf/ask/1708392451/。使用`${4:-$VAR}` 会起作用。 (2认同)
  • +1只是为了详细的答案。但也因为您参考了优秀的 bash wiki。也因为你给出了例子和表格。地狱,一路向下只+1 :) 至于我,我几乎语法正确但不完全 - 我只是不太关心搜索手册页(不难,但我不记得它在什么标题下我从今天早上 4 点就醒了:(.. (2认同)

mik*_*erv 18

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

${var?if unset parent shell dies and this message is output to stderr}
Run Code Online (Sandbox Code Playgroud)

这是我的另一个答案的摘录,我认为它很好地展示了这些是如何工作的:

    sh <<-\CMD
    _input_fn() { set -- "$@" #redundant
            echo ${*?WHERES MY DATA?}
            #echo is not necessary though
            shift #sure hope we have more than $1 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?
Run Code Online (Sandbox Code Playgroud)

来自一个的另一个例子:

    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
Run Code Online (Sandbox Code Playgroud)

上面的例子中利用的所有4所形成POSIX的参数替换和它们的各种:colon nullnot null测试。上面的链接中有更多信息,这里又是

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

最佳

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

#!/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
Run Code Online (Sandbox Code Playgroud)

中间

这是您定义其他函数以根据其结果调用您的打印函数的地方...

    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
    }
Run Code Online (Sandbox Code Playgroud)

底部

您现在已经完成了所有设置,因此您将在此处执行并提取结果。

    _less_important_function
    : "${PLACE:="the cemetery"}" 
    _more_important_function
    : "${RESULT:="regret it."}" 
    _less_important_function    
Run Code Online (Sandbox Code Playgroud)

结果

稍后我将讨论原因,但运行上述代码会产生以下结果:

_less_important_function()'s 第一次运行:

我去你妈妈家看了冰上迪斯尼。

如果你会写书法,你就会成功。

然后 _more_important_function():

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

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

_less_important_function() 再次:

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

如果你做补习数学,你会后悔的。

这个怎么运作:

这里的关键特性是conditional ${parameter} expansion.您可以使用以下形式将变量设置为仅当变量未设置或为空的值的概念:

${var_name:=desired_value}

相反,如果您只想设置一个未设置的变量,则可以省略:colon并且空值将保持原样。

范围:

您可能会注意到,在上面的示例中$PLACE,即使已经调用了$RESULTset via 时parameter expansion也会更改_top_of_script_pr(),大概是在运行时设置它们。这样做的原因是它_top_of_script_pr()是一个( subshelled )函数 - 我将它包含在parens而不是{ curly braces }用于其他函数中。因为它是在子 shell 中调用的,所以它设置的每个变量都是,locally scoped并且当它返回到其父 shell 时,这些值就会消失。

但是当_more_important_function()设置$ACTION它时globally scoped它会影响_less_important_function()'s第二次评估$ACTION因为_less_important_function()设置$ACTION只通过${parameter:=expansion}.


h.j*_*.k. 12

个人经验。

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

$ cat script.sh
SOMETHING="${SOMETHING:-something}"; echo "$SOMETHING"; 
Run Code Online (Sandbox Code Playgroud)

我可以跑:

$ env SOMETHING="something other than the default value" ./script.sh` 
Run Code Online (Sandbox Code Playgroud)

无需更改 的原始默认值SOMETHING