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