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

时间:2016-05-14 14:29:08

标签: linux shell debian posix

考虑以下简单的shell脚本:

rm -rf bar \"bar\"
mkdir -p bar
touch bar/baz
echo "bar"/*

我用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/*

我试图了解posh的行为是否符合POSIX标准或是否是错误。

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

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

  
      
  1. 除非set -f生效,否则应执行路径名扩展(请参阅路径名扩展)。
  2.   
  3. 引用删除(请参阅引用删除)应始终执行。
  4.   

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

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

rm -rf bar \"bar\"
mkdir -p \"bar\"
touch \"bar\"/baz
echo "bar"/*

这是输出:

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/*

因此,posh中的模式"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

3 个答案:

答案 0 :(得分:2)

这是posh 中的错误 - 请参阅错误#636601。从posh版本0.12.6开始,它仍处于打开状态。

附加到该错误的discussion,您会找到patch。应用时,posh的行为与bash类似(因此,在您的第一个示例echo "bar"/*中提供bar/baz)。

此外, bash(以及已修补的 posh)的行为确实符合POSIX 。标准说

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

这意味着 字面上 ,作为纯语法操作,在最后一步删除保护性引号。正如hek2mgl所指出的,引号的语义含义仍将适用于前面的步骤。 (否则,例如像"*"这样的引用根本就没有任何效果。)

所以第二个想法,这个结论是不正确的:

  

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

答案 1 :(得分:0)

即使在quote removal之前,shell也会将不带引号的"视为字符串分隔符,而不是文字字符。

此外,我无法重现您的测试结果。在这两种情况下,bash和posh给了我相同的结果。

答案 2 :(得分:-2)

您可以尝试使用bash --posix(以获得POSIX行为),您会看到结果为bar/baz

重点是" bar"的路径名扩展。给出bar。有关模式匹配un truc th name扩展的详细信息,请参阅SCL第2.13节。