AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 677735
Accepted
MountainX
MountainX
Asked: 2021-11-16 22:29:30 +0800 CST2021-11-16 22:29:30 +0800 CST 2021-11-16 22:29:30 +0800 CST

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

  • 772

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

mounted()true
if
  ...
fi ... && mounted

我想了解那个构造是什么。我在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

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

zsh
  • 1 1 个回答
  • 487 Views

1 个回答

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2021-11-16T22:50:39+08:002021-11-16T22:50:39+08:00

    那是定义函数的 Bourne shell 语法(从 80 年代开始),它并不特定于 zsh。

    在 Bourne shell 中,函数是通过粘贴functionName()在命令前面来定义的¹。

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

    $ name()true
    $ type name
    name is a shell function
    

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

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

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

    在zshseeinfo zsh function中,您应该会看到关于函数定义语法的 Kornfunction关键字的部分。一个扩展zsh是您可以使用相同的主体一次定义多个函数,并使用任何字符串作为函数名称³:

    vrai 1 + $'\1' () true
    faux 0 - $'\0' '' () false
    

    定义几个不同的调用true或false不带参数的函数。

    如果你省略函数名,它会变成一个匿名函数,它可以接受参数并被当场调用:

    () { echo There are $# non-hidden txt files; } *.txt(N)
    

    (尽管出于显而易见的原因,对于能够接受参数的匿名函数,它的主体不能是一个简单的命令)。

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


    现在,使用函数来存储布尔值并不是你经常看到的,但如果你停下来想一想,它确实很有意义。

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

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

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

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

    alias name=false
    myfunction()
      if name; then
        something
      fi
    alias name=true
    myfunction
    

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

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

    name=true name=false
    if eval " $name"; then
      ...
    fi
    

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

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

    name=true name=false
    if "$name"; then
      ...
    fi
    

    我们在其中运行名称存储在$name没有参数的命令的位置。

    或者:

    name=(true) name=(false)
    if "${name[@]}"; then
      ...
    fi
    

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

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

    false=0 true=1
    name=$false name=$true
    
    if expr "$name" > /dev/null; then
      ...
    fi
    if [ "$name" -ne 0 ]; then
      ...
    fi
    

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

    false=0 true=1
    name=$false name=$true
    # or even:
    name=false name=true
    if (( name )); then
      ...
    fi
    

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

    name=true name=false
    if [ "$name" = true ]; then
      ...
    fi
    

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

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

    unset -v name # unset = false
    name=         #   set = true
    if [ -n "${name+true}" ]; then
      ...
    fi
    

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

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

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

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

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

    • 11

相关问题

  • 列出没有其他后缀文件的文件

  • 什么情况下路径中最先找到的可执行文件不会被使用

  • 符号链接所有点文件和目录

  • 如何在`zsh`中增加一个动态命名的变量

  • 为什么我不能在 zsh 中定义一个名为 path 的只读变量?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve