为什么在双引号中指定路径的一部分时,posh无法执行路径名扩展?

Sus*_*Pal 11 linux shell debian posix

考虑以下简单的shell脚本:

rm -rf bar \"bar\"
mkdir -p bar
touch bar/baz
echo "bar"/*
Run Code Online (Sandbox Code Playgroud)

我用bash,ksh,zsh和dash得到了预期的输出,但是我没有用它来得到它:

susam@debian:~$ bash foo.sh
bar/baz
susam@debian:~$ ksh foo.sh
bar/baz
susam@debian:~$ zsh foo.sh 
bar/baz
susam@debian:~$ dash foo.sh
bar/baz
susam@debian:~$ posh foo.sh
bar/*
Run Code Online (Sandbox Code Playgroud)

我试图了解posh的行为是否符合POSIX标准或是否是一个bug.

POSIX文档中的相关部分似乎是"2.6 Word扩展":

他们都提到路径名扩展发生在引用删除之前.

  1. 除非有效,否则应执行路径名扩展(请参阅路径名扩展)set -f.
  2. 报价删除(参见报价删除)应始终执行.

考虑到这一点,豪华行为看起来正确,因为"bar"/*在删除引用之前不会与上面的任何路径字面匹配,因此不会发生路径扩展.

所以这让我怀疑如果有一个字面命名的目录"bar",即引号是目录名称的一部分,那么豪华就会匹配它.但是以下改进的脚本表明这不是真的.

rm -rf bar \"bar\"
mkdir -p \"bar\"
touch \"bar\"/baz
echo "bar"/*
Run Code Online (Sandbox Code Playgroud)

这是输出:

susam@debian1:~$ bash foo2.sh 
bar/*
susam@debian1:~$ ksh foo2.sh 
bar/*
susam@debian1:~$ zsh foo2.sh 
foo2.sh:3: no matches found: bar/*
susam@debian1:~$ dash foo2.sh 
bar/*
susam@debian1:~$ posh foo2.sh 
bar/*
Run Code Online (Sandbox Code Playgroud)

因此"bar"/*,豪华的模式既不匹配路径bar/baz也不匹配路径"bar"/baz.它与之匹配的是什么?豪华行为是错误还是功能?

以下是版本详细信息,以帮助您帮助我:

susam@debian:~$ cat /etc/debian_version 
8.3
susam@debian:~$ dpkg -l bash ksh zsh dash posh
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                        Version            Architecture       Description
+++-===========================-==================-==================-============================================================
ii  bash                        4.3-11+b1          amd64              GNU Bourne Again SHell
ii  dash                        0.5.7-4+b1         amd64              POSIX-compliant shell
ii  ksh                         93u+20120801-1     amd64              Real, AT&T version of the Korn shell
ii  posh                        0.12.3             amd64              Policy-compliant Ordinary SHell
ii  zsh                         5.0.7-5            amd64              shell with lots of features
Run Code Online (Sandbox Code Playgroud)

Ale*_*x O 2

这是一个错误posh- 请参阅错误#636601。从 0.12.6 版本开始它仍然开放posh。

在对该错误的讨论的附件中,您将找到一个补丁。应用时,其posh行为类似于bash(因此在第一个示例中echo "bar"/*给出bar/baz)。

bash此外, (和patched posh )的行为确实符合 POSIX。标准说

  1. 报价删除(请参阅报价删除)应始终最后执行。

从字面上看,这是一个纯粹的语法操作,用于在最后一步中删除保护性引号。正如 hek2mgl 所指出的,引号的语义仍然适用于前面的步骤。(否则,例如像这样的引用"*"根本不会产生任何效果。)

所以转念一想,这个结论并不正确:

考虑到这一点,优雅的行为看起来是正确的,因为“bar”/*在删除引号之前并不与上面的任何路径字面匹配,因此不会发生路径扩展。