zsh 语法是什么?名称()真实

Mou*_*inX 4 zsh

我假设以下块代表一个函数,但它可能不是:

mounted()true
if
  ...
fi ... && mounted
Run Code Online (Sandbox Code Playgroud)

我想了解这个结构是什么。我在zsh的函数标题下没有找到类似的语法

实际代码的更完整片段是:

#! /bin/zsh -p

# leaving out a section...

tmpdir=$(mktemp -d) || exit

mounted()true
if
  mount "$type[@]" -o "${(j[,])opts}" -- "$dev" "$tmpdir"
then
  mount --bind -- "$tmpdir/$subdir" "$dest" || mounted()false
  umount -- "$tmpdir"
fi && rmdir -- "$tmpdir" && mounted
Run Code Online (Sandbox Code Playgroud)

一旦我理解了它,我就会将整个 zsh 脚本转换为我更熟悉的语言。作为中间步骤,我可能会将其转换为 bash。

Sté*_*las 11

这是定义函数的 Bourne shell 语法(来自 80 年代),它不是 zsh 特有的。

\n

在 Bourne shell 中,函数是通过functionName()在命令\xc2\xb9 前面添加来定义的。

\n

因此定义了一个 以简单命令作为其主体name() true调用的函数。nametrue

\n
$ name()true\n$ type name\nname is a shell function\n
Run Code Online (Sandbox Code Playgroud)\n

几乎所有类似 Bourne 的 shell(ksh、ash、dash、bosh、pdksh、mksh、zsh...)都是这种情况。一个值得注意的例外是bash\xc2\xb2 (GNU shell),它最初只允许命令组( { ...; }) 作为函数体,后来将其更改为POSIX语言要求的任何复合命令sh

\n

因此,在 中bash,您需要name()((1))or name()[[ . ]](( ... ))[[ ... ]]ksh\xe2\x80\x94 借用的 \xe2\x80\x94 构造被视为复合命令),或者name() { true; }函数的主体是只有一个简单命令的命令组里面。

\n

请注意,这ksh是第一个引入函数的 shell,尽管具有不同的语法:function name { body; }zsh支持 Korn 和 Bourne 语法,并有自己的扩展。

\n

zshsee中,您应该会看到有关函数定义语法的Korn关键字的info zsh function部分。的一种扩展是,您可以同时定义多个具有相同函数体的函数,并使用任意字符串作为函数名\xc2\xb3:functionzsh

\n
vrai 1 + $\'\\1\' () true\nfaux 0 - $\'\\0\' \'\' () false\n
Run Code Online (Sandbox Code Playgroud)\n

定义一些调用truefalse不带参数的不同函数。

\n

如果省略函数名称,它将成为匿名函数,它可以接受参数并当场调用:

\n
() { echo There are $# non-hidden txt files; } *.txt(N)\n
Run Code Online (Sandbox Code Playgroud)\n

(尽管出于明显的原因,为了使该匿名函数能够接受参数,其主体不能是一个简单的命令)。

\n

在 中zsh,函数也可以通过特殊的关联数组来使用$functions,其中键是函数名称,值是主体中的代码。functions[name]=true定义函数的另一种方法也是如此name

\n
\n

现在,使用函数来存储布尔值并不常见,但如果您停下来思考一下,它确实很有意义。

\n

例如,在 C 语言中,if/while构造或&&/||逻辑运算符作用于数字。如果是非零数则if (condition) something执行。或者哪些类似 C 的语言将其扩展为定义或非空字符串。somethingconditionawkperlcondition

\n

但 shell 位于所有命令行解释器之前。在shell中,一切都是命令。if/while&&/||在大多数 shell 中作用于命令。如果命令成功则if condition; then something; fi执行。somethingcondition

\n

falsetrue是布尔常量命令(内置于大多数 shell 中),它们总是分别失败/成功,因此它们是表示布尔值的明显命令。函数是存储命令(或一般的 shell 代码)最合适的数据结构。

\n

aliases(许多人认为 csh 是一个破坏了的继承,csh 是一个 shell(就像最初的 Bourne shell)没有函数)在这里不起作用,因为别名是在读取包含它们的代码时扩展的,而不是在读取时扩展的。运行。例如在:

\n
alias name=false\nmyfunction()\n  if name; then\n    something\n  fi\nalias name=true\nmyfunction\n
Run Code Online (Sandbox Code Playgroud)\n

函数体实际上包含,if false; then...因为name别名是在读取定义函数的代码时扩展的,而不是在函数运行时扩展的。

\n

可以将代码存储在变量而不是函数中:

\n
name=true name=false\nif eval " $name"; then\n  ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

我们测试命令是否成功,该命令被告知解释4eval中的代码。请注意,在这种情况下,空/未定义(除了选项)会产生true$namenounset$name

\n

或者我们可以这样做(这就是我通常在sh/bash脚本中所做的):

\n
name=true name=false\nif "$name"; then\n  ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

我们运行名称存储在$name不带参数的命令的地方。

\n

或者:

\n
name=(true) name=(false)\nif "${name[@]}"; then\n  ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

我们将简单命令的参数存储在$name 数组变量中。

\n

习惯使用类 C 语言的人可能希望将布尔值存储为整数变量,并运行[/等命令test,或者expr测试从文本表示形式转换后的整数值:

\n
false=0 true=1\nname=$false name=$true\n\nif expr "$name" > /dev/null; then\n  ...\nfi\nif [ "$name" -ne 0 ]; then\n  ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

在类似 Korn 的 shell(包括bashzsh)中,您可以使用((...))计算类似 C 算术表达式的构造,并在生成非零数字(甚至 NaN)时返回成功。

\n
false=0 true=1\nname=$false name=$true\n# or even:\nname=false name=true\nif (( name )); then\n  ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

您还可以运行一个命令来比较字符串(例如[//再次),或者像其他类似 Korn 的构造test一样进行模式匹配:expr[[ string = pattern ]]

\n
name=true name=false\nif [ "$name" = true ]; then\n  ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n

(这对我来说就像if (strcmp(name, "true") == 0)...在 C 中做 a 一样陌生)。

\n

或者即使您愿意,也可以对已定义的变量进行类似awk/的测试。perl

\n
unset -v name # unset = false\nname=         #   set = true\nif [ -n "${name+true}" ]; then\n  ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n
\n

\xc2\xb9 Bourne shell 中存在一个错误(不在其克隆/衍生品5中),但如果您使用带有重定向的简单命令作为函数主体,则该错误无法正常工作,这可能就是 POSIX 的原因只需要支持复合命令作为函数体。

\n

\xc2\xb2 yash(写入 POSIX 规范)posh(基于pdksh但编写是为了帮助验证是否符合标准,因此删除了标准的大多数扩展,包括该扩展)是另外两个例外

\n

\xc2\xb3 这与以下事实一致:外部命令和命令参数可以是任何字符串,因为文件可以包含任何字符串(尽管文件名不能为空,文件名/参数不能包含 NUL 字节) 。在 Bourne shell 中,函数和变量名称共享相同的命名空间(您不能定义具有相同名称的函数和变量),并且函数名称与变量名称具有相同的限制。

\n

4为确保正确性,在前面添加了一个空格,因为某些eval实现不支持--标记选项的结尾

\n

5 zsh 本身过去在函数体中使用重定向时存在其自身的问题,其中大部分已得到修复。但即使是现在,正如文档中明确指出的, in f() { cmd; } < $1,(在主体是带有重定向的命令组的特殊情况下)也不$1是指$1函数范围内的 ,而是指$1调用者的该实例使其不符合 POSIX 标准。这不适用于简单命令或其他类型的复合命令(zsh内部包含在 中{...})。

\n