Shell脚本 - 如果变量为空,则退出脚本

25

我希望在我的bash脚本中使用下面的变量,但是如果它为空或为null,最好的处理方式是什么,如何退出脚本。

tag=$1  

我看到一些答案中使用了 'set -u'。我知道这样做可以运行,但这对于生产环境是否好呢?


1
http://mywiki.wooledge.org/BashGuide/TestsAndConditionals#Conditional_Blocks_.28if.2C_test_and_.5B.5B.29 - Etan Reisner
一个只包含空格的变量,例如 var=" ",应该被视为空还是非空? - Arkadiusz Drabczyk
是的,变量由空格组成被视为空。基本上,我考虑添加一个检查,例如 if [[ ! -z "${Tag}" && "${Tag}" != ’’ ]]。 - Pinaki Mukherjee
7个回答

41

有一个内置的运算符,可以要求设置变量。如果变量没有被设置,脚本将退出。

tag=${1?Need a value}

通常这与脚本开头的: no-op一起使用。

: ${1?Need a value}

"unset or empty"的合并有所不同。没有类似的结构可以在空但已设置的值上退出,但您可以轻松使用相关语法${var:-default},它展开为$var如果它被设置并且非空,否则为default。还有${var-default},仅在变量正确未设置时才产生default

当您需要应对可能未设置的变量时,这可能特别有用,但又想使用set -u

case ${var-} in '') echo "$0: Need a value in var" >&2; exit 1;; esac

我有点倾向于使用 case 而不是 if [ "${var-}" = '' ],主要是因为这样可以避免我在 ${var-} 周围加上双引号,并且可以避免 $var 中的值被解释为一个选项并在最不希望出现错误消息的时候给你一个错误提示。(在 Bash 中,[[ 没有这些问题;但我更喜欢尽可能地坚持 POSIX shell。)


21

如果您想测试一个变量是否为非空值,您可以这样做:

if [ -z "$tag" ]; then
    exit 1
fi

test的手册中得知:

-z STRING

STRING长度为零

如果您正在使用脚本的位置参数,您还可以通过查看$#来测试接收到的参数数量。


2
你需要在"$tag"周围加上引号,否则在空字符串上会失败(试一下就知道)。 - Etan Reisner

8
没有人提出 :? 选项。
如果您希望确保变量被设置且不为null:
SEARCH_PATH=${DAYS_TO_KEEP:?Must provide DAYS_TO_KEEP.}

将立即以2的代码退出并打印一条消息:

/entrypoint.sh: line 17: SEARCH_PATH: Must provide DAYS_TO_KEEP.

这在我的Ubuntu上以1退出。另外,这与tripleee的已接受答案有什么区别? - derpedy-doo
如上所述,这是用户可以使用的不同选项,以确保变量存在且不为空。 - Pav K.
1
所以这里唯一的区别就是你的代码还检查了 null 值吗?而被接受的答案没有检查 null 值?那真是太棒了!我会在你的答案中更清晰地表明这个区别,以便更强烈地区分你的答案和被接受的答案 :slightly_smiling_face: - derpedy-doo

4

我不确定您想检测变量是否未设置还是为空。这两个是不同的。具体而言,一个变量可以被设置但为空:

$ var=""
$ if [ -z "$var" ]; then echo empty; fi
$ empty

这里也是一样的情况:
#!/usr/bin/env bash

set -u
echo $1

测试:

$ ./test.sh
./test.sh: line 4: $1: unbound variable
$ ./test.sh ""

$

或在这里:

#!/usr/bin/env bash

tag=${1?Need a value}
echo $tag

测试:

$ ./se.sh
./se.sh: line 3: 1: Need a value
$ ./se.sh ""

$

其他海报已经介绍了检测未设置和空变量的正确方法。个人喜欢这种检测空和未设置变量的方式:

#!/usr/bin/env bash

if [ "$1"A = A ]
then
    echo variable is empty or unset
fi

测试:

$ ./empty.sh ""
variable is empty or unset
$ ./empty.sh
variable is empty or unset
$ ./empty.sh 1
$

1
"$1"A 方法在任何现代的 shell 实现中都是不必要的。这是一个 hack,旧的 shell 无法处理 test 命令的显式空参数。[ "$1" = "" ] 同样可以很好地处理空/未设置的 $1 - chepner
这并不是必须的,但我个人喜欢。这只是个人偏好的问题。 - Arkadiusz Drabczyk

1
使用模式匹配来检测值是否仅由空格组成:
pattern=$'*( |\t)'
if [[ $1 = $pattern ]]; then
    echo "First parameter has no non-whitespace characters"
    exit 1
fi
$'...' 的引用使字符串中添加制表符更加容易。扩展模式 *(...) 匹配圆括号内的模式0次或多次(类似于正则表达式 ( |\t)*)。将模式分配给变量,因为如果右操作数的任何部分被引用,= 执行精确字符串匹配,因此我们事先进行引用以便更轻松地设置该值。

你需要启用扩展的 globbing 才能使其工作,不是吗? - tripleee
也许吧。在新版本的 bash(4.2 及以后?)中,暂时会在 [[... ]] 内部打开扩展通配符,因此无需显式地执行此操作。否则,是的,需要使用 shopt -s extglob - chepner

1

我比较喜欢Perl使用的"die",在shell中也很容易实现类似的功能。

# Print (optional) error message and exit
# Usage: die [[msg] exit_status]
die() {
    [[ -n "$1" ]] && echo "$1"
    [[ -n "$2" ]] && exit $2 || exit 1
}

[[ -n "$tag" ]] || die "Need a tag argument.  Use $0 --help for details"

这假设使用Bash或Korn shell,但可以通过将 [[]] 更改为 [] 来转换为经典的Bourne shell。

0
以下测试确保变量为Null或已分配值。双引号非常重要,必须使用!
VAL= # Creates a NULL variable
if [[ -z "$VAL" && "$VAL" = ’’ ]]
then
echo "The VAL variable is NULL"
fi
or
VAL=25
if [[ ! -z "$VAL" && "$VAL" != ’’ ]]
then
echo "The VAL variable is NOT NULL"
fi

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