当我按下回车键时
(cd <somewhere>/; ls -gG S09E03*
我预计会出现错误,因为目录中没有任何文件匹配S09E03*
(我已经验证了这一点),但该命令显示了有关我想要的信息的文件的信息。
所以看起来我的 shell(修补过的 Debian Buster 上的 zsh,即版本 5.7.1)直到它位于正确的目录中(即在 后cd
)才进行通配。cd
是一个内置的(它基本上必须是),所以我想 shell 知道我希望它发生在哪里?
我彻底没了吗?相反,它与子 shell 有什么关系 -(cd <somewhere1>; ls -l <prefix>*; cd <somewhere2>; ls -l <prefix>*)
显示有关两个不同文件的信息,所以我不这么认为,但我可能(再次)错了?或者是其他东西延迟了通配符(相对于我的想法。
<somewhere>
很长,所以我试图避免在输出中得到该路径ls
ls -gG
因为我知道文件的所有者和组在我想比较的一些属性的文件之间会有所不同
答案1
Shell(不仅仅是 zsh)完成解析之前的命令扩大进而执行它。
- 解析根据以下内容分解输入shell语法。此步骤包括识别哪些字符是单词分隔符、保留字符、命令运算符、重定向运算符、文档标记、引号等。
- 执行命令会评估命令运算符(
;
、&
、|
等),并且对于简单命令,执行参数分配,重定向和扩展从左到右。 - 执行时会调用外部命令,内置或功能(如果有)。
请注意,我在这里只是给出一个非常笼统的概述。一些极端情况可能很棘手并且依赖于 shell,我不会在这篇文章中讨论这些情况。
当给定 时(cd subdir/; ls -gG S09E03*)
,shell 首先解析它以获得以下结果:
- 正在运行的子 shell:
- 两个命令的序列:
- 一个简单的命令,由两个普通单词组成:
cd
,subdir/
(不带引号字符)。 - 一个简单的命令,由三个普通单词组成:
ls
,-gG
,S09E03*
(不带引号字符)。
- 一个简单的命令,由两个普通单词组成:
- 两个命令的序列:
这与 shell 执行的工作相同,例如,如果它正在处理函数定义
f () {
(cd subdir/; ls -gG S09E03*)
}
一旦解析了命令,shell 就会执行它。它为子 shell 构造创建一个子 shell。在子 shell 内,它首先展开然后执行第一个简单命令,然后展开然后执行第二个命令。当前目录subdir/
在执行第一个简单命令期间更改为。的扩展S09E03*
(即通配步骤发生的位置)稍后发生。
顺便说一句,子shell只是一个细节,不会改变任何东西。重要的是;
分隔两个命令,并且第一个命令在第二个命令之前执行。
这并不是说“shell 知道我希望它在哪里发生”——它就在它发生的地方发生。命令参数的扩展始终发生在与命令本身相同的目录中(执行命令的任何部分都不能更改其当前目录,除了最后一步可以调用内置函数来执行此操作或在函数内执行此操作)。