zsh 中波形符的扩展

zsh 中波形符的扩展

我在使用 FreeBSD 时偶然发现了 zsh 的这种行为:

% dd if=/dev/zero bs=1M count=1 of=~/test2
dd: failed to open '~/test2': No such file or directory

这真的让我很困惑,因为同样的事情在 bash 中工作得很好。

我可以touch在 zsh 中使用波形符来文件,然后ls它们:

% touch ~/test2
% ls ~/test2
/home/christoph/test2

起初,我假设 zsh 没有意识到后面有一条路径,of=所以它没有扩展~。但自动完成文件名效果很好。事实上,如果使用现有文件名,以 开头其路径~,然后在某个时刻按 Tab 键,该路径会在我输入的命令中展开。

为什么 zsh 传递~/test2dd,而不是/home/christoph/test2

zsh 在 Linux 上的行为相同。事实上,我执行了上面的这些命令并在 Linux 机器上复制了它们的输出。

答案1

~仅在少数情况下扩展。 POSIX,用于标准sh要求echo a=~输出a=~(同时要求单独~扩展a=~)。

zsh但是有一个magicequalsubst选项,您可以使用该选项~在 ¹ 之后进行扩展,=即使它不在export/ typeset... 伪关键字的赋值或参数中。

所以:

$ echo a=~
a=~
$ set -o magicequalsubst
$ echo a=~
a=/home/chazelas

请注意bash,当不在 POSIX/sh模式下时,仅当 左侧的内容看起来像字面的不带引号的变量名时才展开~in (无论它是否在 // 或任何其他命令的参数中):word=~=bashtypesetdeclareexport

$ bash -c 'echo a=~'
a=/home/chazelas
$ bash -c 'echo "a"=~'
a=~
$ bash -c 'var=a; echo $var=~'
a=~
$ bash -c 'echo a.b=~'
a.b=~
$ (exec -a sh bash -c 'echo a=~')
a=~

在任何情况下,您始终可以使用$HOME(~echo a=$HOMEzsh 中,echo "a=$HOME"在其他类似 Bourne 的 shell 中,其中需要引用参数扩展以防止 split+glob²)。


仅限文字和未引用的内容,或由globsubst启用的扩展产生的内容,其中文件名扩展(从.....分离通配又名文件名生成)~是 的一种形式,只要shfileexpansion未启用(如在sh仿真中),就会执行。你会发现这var='a=~' zsh -o magicequalsubst -o globsubst -c 'echo $var'两个var='a=~' zsh -o magicequalsubst -c 'echo $~var'输出a=/home/dir

² 波形符扩展本身不会经历 split+glob,除非在旧版本的 bash 中它曾经经历过 globbing。无论如何,波浪线扩展不会在双引号内执行。

相关内容