变量中的全局字符在 bash 中扩展,但在 zsh 中不扩展

变量中的全局字符在 bash 中扩展,但在 zsh 中不扩展

我发现 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 中的所有变量。bashsh

例如参见:忘记在 bash/POSIX shell 中引用变量的安全隐患

我发现你在写作时也期待着这一点echo $0,而不是echo "$0"

zsh已经解决了这个问题。默认情况下,它在参数扩展时既不进行通配也不进行分词。您需要明确请求这些:

  • echo $=file:执行分词
  • echo $~file: 执行通配符
  • echo $=~file: 执行两者

或者您可以打开globsubst和选项来获得与类似 Bourne 的 shell 中相同的行为(为了兼容性而调用shwordsplit时启用这两个选项),但我不建议这样做,除非您需要解释为另一个 shell 编写的代码(即使在这种情况下,使用 ) 在本地上下文中模拟解释该代码也会更有意义。zshshshzshshemulate -L sh

这里命名你的file变量

file=*

如果您打算在扩展时扩展它,这是误导性的

filename_pattern=*

会更有意义。如果您想要一个变量保存当前目录中所有非隐藏文件的名称,您可以这样做:

files=(*)

或者:

files=(*(N))

如果当前目录中没有非隐藏文件,则该分配不会失败。

也就是说,使用一个大批变量赋值。 ( file=(*)) 的工作方式与bashor ksh93mkshor相同yash,只不过它zsh没有 Bourne shell 的其他错误特征,即当没有匹配项时模式不会展开。


*¹请注意,对于类 Unix 系统上的文件来说,这是一个完全有效的名称。我感到有些安慰的是,即使该文件被称为 ,rm -f -- $file也会删除其名称存储在其中的文件。$file*

相关内容