Bash 抛出错误,第 8 行:$1:未绑定变量

Tim*_*iam 42 scripting bash shell-script

我正在尝试学习如何使用 getopts 以便我可以使用解析输入的脚本(尽管我认为 getopts 可能会更好)。我正在尝试编写一个简单的脚本来返回分区使用百分比。问题是我的 bash 函数之一似乎不喜欢我$1在函数中作为变量引用。我引用的原因$1是因为该get_percent函数可以将挂载点作为可选参数传递给 display 而不是所有挂载点。

剧本

#!/usr/bin/bash

set -e
set -u
set -o pipefail

get_percent(){
    if [ -n "$1" ] 
    then
        df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
    else
        df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
    fi
}

usage(){
    echo "script usage: $(basename $0) [-h] [-p] [-m mount_point]" >&2
}

# If the user doesn't supply any arguments, we run the script as normal
if [ $# -eq 0 ];
then
    get_percent
    exit 0
fi
# ...
Run Code Online (Sandbox Code Playgroud)

输出

$ bash thing.sh
thing.sh: line 8: $1: unbound variable

$ bash -x thing.sh
+ set -e
+ set -u
+ set -o pipefail
+ '[' 0 -eq 0 ']'
+ get_percent
thing.sh: line 8: $1: unbound variable
Run Code Online (Sandbox Code Playgroud)

Dop*_*oti 63

set -u如果您引用尚未设置的变量,将完全按照您的描述中止。您正在不带参数调用脚本,因此在不带参数的情况下调用脚本get_percent,导致未$1设置。

在调用您的函数之前检查这一点,或者使用默认扩展(如果尚未设置为其他内容,${1-default}将扩展为default)。

  • 特别是,可以使用`[ -n "${1-}" ]`(即默认值为空)来查看参数是否已设置且非空;或 `[ "${1+x}" = x ]` 以查看它是否已设置,即使为空。 (13认同)
  • @ChaitanyaBapat 在我使用 `:-` 而不是 `-` 之前,我仍然得到了 `unbound variable`。所以,至少对我来说,`${1:-default}` 不会引发错误。 (2认同)

Ral*_*edl 11

这是 的效果set -u

如果未设置,您可以检查$#函数内部并避免引用$1

$#你可以访问的参数数量。在全局上下文中,它是脚本的参数数量,在函数中,它是函数的参数数量。

在问题的背景下,它是

if [ $# -ge 1 ] && [ -n "$1" ]
then
    df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
else
    df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
fi
Run Code Online (Sandbox Code Playgroud)

请注意,您必须使用[ $# -ge 1 ] && [ -n "$1" ]and not [ $# -ge 1 -a -n "$1" ],因为那将首先评估$1然后检查$#


Jas*_*sha 10

其他答案都提到了这是 的效果set -u。其他答案都没有提到set -u可以通过以下方式逆转set +u

$ echo $VAR  # nothing echoed below as VAR is unset:

$ set -u
$ echo $VAR
bash: VAR: unbound variable
$ set +u
$ echo $VAR  # nothing echoed below as VAR is unset:

Run Code Online (Sandbox Code Playgroud)


Mic*_*ski 8

使用脚本中的“set -u”,任何对未设置变量的引用都会导致错误,特别是测试它是否有值,这就是脚本正在执行的操作。

以下函数将测试未设置的变量,而不会触发 set -u:

if:IsSet() {
  [[ ${!1-x} == x ]] && return 1 || return 0
}
Run Code Online (Sandbox Code Playgroud)

使用它:

if:IsSet someVariableName || echo "someVariableName is not set"

至于实际的函数,测试是否传入了参数,而不是测试是否为空。这将避免未设置变量的问题,而无需采取任何特殊步骤,例如测试变量是否有值。

get_percent(){
    if [ ${#1} -eq 0 ] 
Run Code Online (Sandbox Code Playgroud)

顺便说一句:函数名称中的冒号只是一个字符。它在 Bash 中的函数名称中有效,如 %、}、{、[ 和其他一些:-)

  • 如果“someVariableName”恰好设置为“x”,则此方法不起作用。您可以使用 `[[ ${!1-x} == x ]] && [[ ${!1-y} == y ]] && return 1; 来修复它 在 `if:IsSet` 函数中返回 0`。 (2认同)

roa*_*ima 6

因为这是你可以绕过对设置的bash检查,只使用(是第一个参数,是所有参数;当用双引号引起来时,如果它没有值,它会完全消失,这可以避免它被 捕获):$1"$@"$1$@set -u

get_percent() {
    df -h "$@" | awk 'NR>1 { printf "%s\t%s\n", $1, $5 }'
}
Run Code Online (Sandbox Code Playgroud)

我还稍微调整了该行的其余部分,这样您输出的两个值之间就不会出现 {space}{tab}{space} ,但您只会得到一个 {tab} 。如果您确实想要两个不可见的空间,请更改awk为使用printf "%s \t %s\n", $1, $5