为什么在 POSIX sh 中的 `test`/`[` 字符串比较中附加一个额外的字符?

Why append an extra character in `test`/`[` string comparison in POSIX sh?

在阅读了 Debian 的 /usr/bin/startx 之后,我发现了一些奇怪的东西:

mcookie=`/usr/bin/mcookie`

if test x"$mcookie" = x; then
    echo "Couldn't create cookie"
    exit 1
fi

我不明白为什么额外的 x 是必要的 - 不是等同于写以下内容吗?

mcookie=`/usr/bin/mcookie`

if test "$mcookie" = ""; then
    echo "Couldn't create cookie"
    exit 1
fi

我最初认为如果 mkcookie 变量碰巧未设置,sh 的早期版本可能会打印出一些错误(这不是唯一的例子;这些类型的比较是分散的在整个脚本中自由地)。但是经过进一步思考并没有多大意义,因为变量被引用并且 shell 会将其扩展为空字符串。

我仔细阅读了 Bash 手册页的 Dash,--posix 部分并检查了 POSIX 本身。它在 test: s1 = s2 True if the strings s1 and s2 are identical; otherwise, false 下什么也没说。我假设编写脚本的人知道他们在做什么 - 那么有人可以阐明这一点吗?

谢谢, 埃德温

以下是 Wooledge Bash Pitfall #4 的摘录:

You may have seen code like this:

[ x"$foo" = xbar ] # Ok, but usually unnecessary.

The x"$foo" hack is required for code that must run on very ancient shells which lack [[, and have a more primitive [, which gets confused if $foo begins with a -. On said older systems, [ still doesn't care whether the token on the right hand side of the = begins with a -. It just uses it literally. It's just the left-hand side that needs extra caution.

Note that shells that require this workaround are not POSIX-conforming. Even the Heirloom Bourne shell doesn't require this (probably the non-POSIX Bourne shell clone that's still most widely in use as a system shell). Such extreme portability is rarely a requirement and makes your code less readable (and uglier).

如果您在本世纪的代码中发现它,那只是货物崇拜不断被不引用的人强化。

/usr/bin/startx 至少从 1993 年 2 月的 XFree86 2.1 开始就特别使用这个习惯用法,并且从那以后任何更新都可能只是匹配样式。