我假设以下块代表一个函数,但它可能不是:
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 前面添加来定义的。
因此定义了一个 以简单命令作为其主体name() true
调用的函数。name
true
$ 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
因此,在 中bash
,您需要name()((1))
or name()[[ . ]]
((( ... ))
从[[ ... ]]
ksh\xe2\x80\x94 借用的 \xe2\x80\x94 构造被视为复合命令),或者name() { true; }
函数的主体是只有一个简单命令的命令组里面。
请注意,这ksh
是第一个引入函数的 shell,尽管具有不同的语法:function name { body; }
。zsh
支持 Korn 和 Bourne 语法,并有自己的扩展。
在zsh
see中,您应该会看到有关函数定义语法的Korn关键字的info zsh function
部分。的一种扩展是,您可以同时定义多个具有相同函数体的函数,并使用任意字符串作为函数名\xc2\xb3:function
zsh
vrai 1 + $\'\\1\' () true\nfaux 0 - $\'\\0\' \'\' () false\n
Run Code Online (Sandbox Code Playgroud)\n定义一些调用true
或false
不带参数的不同函数。
如果省略函数名称,它将成为匿名函数,它可以接受参数并当场调用:
\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例如,在 C 语言中,if
/while
构造或&&
/||
逻辑运算符作用于数字。如果是非零数则if (condition) something
执行。或者哪些类似 C 的语言将其扩展为定义或非空字符串。something
condition
awk
perl
condition
但 shell 位于所有命令行解释器之前。在shell中,一切都是命令。if
/while
和&&
/||
在大多数 shell 中作用于命令。如果命令成功则if condition; then something; fi
执行。something
condition
false
和true
是布尔常量命令(内置于大多数 shell 中),它们总是分别失败/成功,因此它们是表示布尔值的明显命令。函数是存储命令(或一般的 shell 代码)最合适的数据结构。
alias
es(许多人认为 csh 是一个破坏了的继承,csh 是一个 shell(就像最初的 Bourne shell)没有函数)在这里不起作用,因为别名是在读取包含它们的代码时扩展的,而不是在读取时扩展的。运行。例如在:
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
别名是在读取定义函数的代码时扩展的,而不是在函数运行时扩展的。
可以将代码存储在变量而不是函数中:
\nname=true name=false\nif eval " $name"; then\n ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n我们测试命令是否成功,该命令被告知解释4eval
中的代码。请注意,在这种情况下,空/未定义(除了选项)会产生true$name
nounset
$name
。
或者我们可以这样做(这就是我通常在sh
/bash
脚本中所做的):
name=true name=false\nif "$name"; then\n ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n我们运行名称存储在$name
不带参数的命令的地方。
或者:
\nname=(true) name=(false)\nif "${name[@]}"; then\n ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n我们将简单命令的参数存储在$name
数组变量中。
习惯使用类 C 语言的人可能希望将布尔值存储为整数变量,并运行[
/等命令test
,或者expr
测试从文本表示形式转换后的整数值:
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(包括bash
和zsh
)中,您可以使用((...))
计算类似 C 算术表达式的构造,并在生成非零数字(甚至 NaN)时返回成功。
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 ]]
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 一样陌生)。
或者即使您愿意,也可以对已定义的变量进行类似awk
/的测试。perl
unset -v name # unset = false\nname= # set = true\nif [ -n "${name+true}" ]; then\n ...\nfi\n
Run Code Online (Sandbox Code Playgroud)\n\xc2\xb9 Bourne shell 中存在一个错误(不在其克隆/衍生品5中),但如果您使用带有重定向的简单命令作为函数主体,则该错误无法正常工作,这可能就是 POSIX 的原因只需要支持复合命令作为函数体。
\n\xc2\xb2 yash
(写入 POSIX 规范)posh
(基于pdksh
但编写是为了帮助验证是否符合标准,因此删除了标准的大多数扩展,包括该扩展)是另外两个例外
\xc2\xb3 这与以下事实一致:外部命令和命令参数可以是任何字符串,因为文件可以包含任何字符串(尽管文件名不能为空,文件名/参数不能包含 NUL 字节) 。在 Bourne shell 中,函数和变量名称共享相同的命名空间(您不能定义具有相同名称的函数和变量),并且函数名称与变量名称具有相同的限制。
\n4为确保正确性,在前面添加了一个空格,因为某些eval
实现不支持--
标记选项的结尾
5 zsh 本身过去在函数体中使用重定向时存在其自身的问题,其中大部分已得到修复。但即使是现在,正如文档中明确指出的, in f() { cmd; } < $1
,(在主体是带有重定向的命令组的特殊情况下)也不$1
是指$1
函数范围内的 ,而是指$1
调用者的该实例使其不符合 POSIX 标准。这不适用于简单命令或其他类型的复合命令(zsh
内部包含在 中{...}
)。
归档时间: |
|
查看次数: |
635 次 |
最近记录: |