我正在阅读 bash 脚本,我不明白那里发生了什么。
#!/bin/sh
[ x$1 = x ]
第二行发生了什么,什么[ x$1 = x ]
意思?
答案1
它检查它$1
是否为空,尽管它应该被引用(与 相同[ -z "$1" ]
)。一些非常古老的 shell 无法正确处理空字符串,因此可移植脚本的编写者采用了这种检查方式。几十年来,这已经没有必要了,但人们仍然这样做,因为人们仍然这样做。
答案2
方括号表示测试,所以[ x$1 = x]
没有if
或类似的东西是没有意义的,尽管语法上没问题。
x$1
如果扩展为,则计算结果为 true ,x
否则为 false ,但由于它未加引号,如果$1
是(例如)“hey x”,shell 将看到x = x
,因此这种构造仍然不安全。
检查的目的x = x
是确定变量是否为空。更常见的方法是仅使用引号:
if [ "$1" = "" ]; then
Bash 测试操作符-z
也-n
可以使用,但它们对于其他类型的 shell 的可移植性较差。1
使用引号或 的原因x$1
是为了使左侧不会扩展为空,这将是语法错误:
if [ = x ] # No good!
if [ "" = "" ] # Okay.
if [ x = x ] # Also okay.
1. 实际上,test
可以是独立的实用程序,但大多数 shell 将其实现为内置的;检查which test
和之间的差异type test
。在 GNU/Linux 上man test
声称引用了内置函数,但如果您调用 (eg) /usr/bin/test
,该实用程序似乎实现了手册页中记录的功能,包括-z
和-n
。
答案3
[ x$1 = x ]
仅在zsh
.这会将x
与脚本的第一个参数的串联与 进行比较x
。因此,如果为空或未提供,该[
命令将返回 true 。$1
[ $1 = "" ]
不起作用,因为zsh
当列表上下文中未引用空变量时,它会扩展为根本没有参数而不是空参数,因此如果$1
未设置或为空,则[
命令将仅接收作为参数[
, =
,空字符串这是]
无法理解的。[ -z "$1" ]
或者[ "$1" = "" ]
像在 POSIX shell 中那样也可以。
在 Bourne-like/POSIX shell 中,[ x$1 = x ]
没有意义。这是 split+glob 运算符以某种方式应用于x
脚本的第一个参数的串联,希望结果 和=
,x
和]
组成[
命令的有效测试表达式。
例如,如果脚本传递一个" = x -o x ="
参数,[
则将接收这些参数:[
, x
, =
, x
, -o
, x
, =
, x
, ]
,这[
将被理解为x
与x
和x
进行比较x
并返回 true。
如果$1
是"* *"
,则 shell 会将[
当前目录中名称以 开头的文件列表x
( 的 glob 扩展x*
)传递给命令,然后是非隐藏文件列表(扩展*
)……这[
不太可能产生任何意义。唯一有意义的情况是,如果$1
不包含通配符或空白字符。
现在,您有时会发现如下代码:
[ "x$1" = x ]
用于测试是否$1
为空或未设置。
测试空或未设置变量的正常方法是:
[ -z "$1" ]
但是,对于某些(非 POSIX)实现中的某些$1
值(例如Solaris 10 及之前版本的 Bourne shell 中的内置值)或某些旧版本(最高至 0.5.4)或某些 BSD 的某些值,该方法会失败。=
[
/bin/sh
dash
sh
这是因为[
看到[
、-z
、=
和]
抱怨=
二元运算符缺少参数,而不是将其理解为-z
应用于=
字符串的一元运算符。
同样,if is or[ "$1" = "" ]
的某些实现也会失败。[
$1
!
(
在这些 shell/[
实现中:
[ "x$1" = x ]
无论 的值如何,始终是有效的测试$1
,因此:
[ "" = "$1" ]
和:
[ -z "${1:+x}" ]
和
case $1 in "") ...; esac
当然,如果你想检查是否没有提供任何参数,你可以这样做:
[ "$#" -eq 0 ]
也就是说,您检查传递给脚本的参数数量。
请注意,如今,[ -z "$var" ]
是由 POSIX 明确指定的,并且在一致性实现中不会失败[
(并且bash
'[
已经存在了几十年)。所以你应该能够在 POSIX sh 或bash
脚本中依赖它。
答案4
[ x$1 = x ]
$1
如果unset/null/empty 则为true 。
尝试一下:
TEST= ;[ x$TEST = x] && echo "TEST is unset"
和
TEST=lolz ;[ x$TEST = x ] && echo "TEST is unset"