应如何处理由变量扩展引起的反斜杠?

How should a backslash resulting from variable expansion be treated?

我 运行 以下命令(*shsh 实现的名称)以及我能找到的所有 shell;虽然我期望所有的打印 match,但我得到的结果不一致。我不知道哪种行为是正确和可靠的。

*sh -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'

dash from Ubuntu bionic's repo(和灰;这是一个象征性的link来破折号)

$ dash -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
match

使用 bash 4.4.20(1)-release (x86_64-pc-linux-gnu) 和 5.0.11(1)-release (arm-unknown-linux-androideabi)

$ bash -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
match

使用 ksh 版本 AJM 93u+ 2012-08-01 和版本 JM 93t+ 2010-03-05(预装 SunOS omniosce 5.11)

$ ksh -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
match

使用 ksh @(#)PD KSH v5.2.14 99.07.13.2(OpenBSD 6.6 上的默认值 shell,以及 its Linux port

$ ksh -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
$

使用 lksh @(#)LEGACY KSH R56 2018/01/14、mksh @(#)MIRBSD KSH R56 2018/01/14(这些是 Ubuntu bionic 上的不同二进制文件)和 mksh @ (#)MIRBSD KSH R57 2019/03/01

$ lksh -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
$ mksh -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
$ 

带有豪华版 0.13.1

$ posh -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
$ 

带 yash 2.46

$ yash -c 'case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
$ 

以及 zsh 5.4.2 (x86_64-ubuntu-linux-gnu) 和 5.7.1 (arm-unknown-linux-androideabi);模拟 sh

$ zsh -c 'emulate sh; case "" in ) echo match; esac' _ 'f\oo' 'f\oo'
match

我迷失在POSIX's Shell Command Language specification;还不能找到我的问题的直接答案:如何在 glob 模式中解释由变量扩展引起的转义反斜杠?作为 \ 或作为 \? 还是未指定?


Case Conditional Construct 下面说:

In order from the beginning to the end of the case statement, each pattern that labels a compound-list shall be subjected to tilde expansion, parameter expansion, command substitution, and arithmetic expansion, and the result of these expansions shall be compared against the expansion of word, according to the rules described in Pattern Matching Notation (which also describes the effect of quoting parts of the pattern)

注意它并没有说模式会被引号删除;但在模式匹配符号下,它说:

A <backslash> character shall escape the following character. The escaping <backslash> shall be discarded

但是当模式是扩展的结果时,它是否仍然会发生这种情况并不清楚。


对于任何感兴趣的人,标准都不清楚;不过,他们会在更新的版本中对其进行修改。下面是一些 link 到 POSIX 错误报告,其中广泛讨论了这个问题。

也许这一点参考可以解决您的问题。从 POSIX's Shell Command Language specification - under Pattern Matching Notation 条款开始,

2.13.1 Patterns Matching a Single Character

A <backslash> character shall escape the following character. The escaping <backslash> shall be discarded. If a pattern ends with an unescaped <backslash>, it is unspecified whether the pattern does not match anything or the pattern is treated as invalid

以上规则适用于使用 case 语句和在 bash 中使用 test 构造的 == glob 匹配运算符的模式。

因此,由于您的 </code> 在进行模式匹配时仍未被引用,因此 <code>f\oo 的字面值将永远丢失并被解释为 f\oo.

只是为了澄清一下,shell 在删除引号期间保留了您的字面值,并且仅当在此模式匹配规则中应用传递的参数时,才会出现此行为。