Bru*_*son 4 zsh wildcards variable-substitution
我看到 zsh 的一个问题,其中变量中的 glob 字符没有像我预期的那样扩展。下面的例子可以更好地解释它。
$ echo $0
-bash
$ echo $HOME/Downloads/zsh-test/*
/Users/bruce/Downloads/zsh-test/file1 /Users/bruce/Downloads/zsh-test/file2 /Users/bruce/Downloads/zsh-test/file3 /Users/bruce/Downloads/zsh-test/file4
$ file=*; echo $HOME/Downloads/zsh-test/$file
/Users/bruce/Downloads/zsh-test/file1 /Users/bruce/Downloads/zsh-test/file2 /Users/bruce/Downloads/zsh-test/file3 /Users/bruce/Downloads/zsh-test/file4
Macbook% echo $0
zsh
Macbook% echo $HOME/Downloads/zsh-test/*
/Users/bruce/Downloads/zsh-test/file1 /Users/bruce/Downloads/zsh-test/file2 /Users/bruce/Downloads/zsh-test/file3 /Users/bruce/Downloads/zsh-test/file4
Macbook% file=*; echo $HOME/Downloads/zsh-test/$file
/Users/bruce/Downloads/zsh-test/*
Run Code Online (Sandbox Code Playgroud)
我原以为最后一个命令会像在 bash 中那样扩展。知道我做错了什么吗?
Sté*_*las 14
那将是我第一次看到有人抱怨这个(我们更经常看到人们抱怨它没有在参数扩展时进行分词)。
大多数人期待
echo $file
Run Code Online (Sandbox Code Playgroud)
输出$file
变量的内容并且当 shell 像bash
不一样时感到恼火(从 Bourne shell 继承的行为,不幸的是没有被 ksh 修复并由 POSIX 为sh
解释器指定),这导致了很多错误和安全漏洞和这就是为什么您需要引用这些 shell 中的所有变量的原因。
例如,请参阅:忘记在 bash/POSIX shell 中引用变量的安全隐患
我看到您在写作时也期待这一点,echo $0
而不是echo "$0"
。
zsh
已经解决了。默认情况下,它在参数扩展时既不进行通配也不进行分词。您需要明确请求这些:
echo $=file
: 进行分词echo $~file
: 执行通配echo $=~file
: 两者都执行或者您可以打开globsubst
和shwordsplit
选项以获得与类似 Bourne 的 shell 相同的行为(为了兼容性zsh
而调用这两个选项时启用这两个选项),但我不建议这样做,除非您需要解释为另一个 shell 编写的代码(即使在这种情况下,在本地上下文中模拟解释该代码也会更有意义)。sh
sh
zsh
sh
emulate -L sh
这里命名您的变量file
中
file=*
Run Code Online (Sandbox Code Playgroud)
如果您打算在扩展时扩展它,则具有误导性¹
filename_pattern=*
Run Code Online (Sandbox Code Playgroud)
会更有意义。如果你想要一个变量来保存当前目录中所有非隐藏文件的名称,你可以这样做:
files=(*)
Run Code Online (Sandbox Code Playgroud)
或者:
files=(*(N))
Run Code Online (Sandbox Code Playgroud)
如果当前目录中没有非隐藏文件,则该分配不会失败。
即,使用数组变量赋值。该 ( file=(*)
) 与bash
or ksh93
, mksh
or 中的工作方式相同yash
,只是它zsh
没有 Bourne shell 的其他错误特征,即在没有匹配项时不展开模式。
¹请注意,*
对于类 Unix 系统上的文件来说,这是一个完全有效的名称。我感到有些欣慰rm -f -- $file
的是,$file
即使该文件被称为*
.