从 zsh 运行时,Bash 脚本抛出“分配给无效下标范围”

Ayu*_*man 4 bash zsh

更新 查看此链接,我更新了数组下标以 1 而不是 0 开头,并且看起来数组变量已正确读取。

#!/bin/bash

#Root folders for Git update.
    ROOT[1]="/Users/ayusman/dev/repos1"
    ROOT[2]="/Users/ayusman/dev/repos2"

#do some things with the ROOT variable.
Run Code Online (Sandbox Code Playgroud)

但我开始在其他地方看到错误,因为我之前声明的 shell 函数未被识别。

未找到命令:git

所以我认为普遍的问题是:

如何将在 bash shell 中运行的完美运行的 shell 脚本移植到 zsh shell?

我最近将 Mac 升级到 macOS Catalina 10.15.2

我的 shell 脚本之一如下所示:

#!/bin/bash

#Root folders for Git update.
    ROOT[0]="/Users/ayusman/dev/repos1"
    ROOT[1]="/Users/ayusman/dev/repos2"

#do some things with the ROOT variable.
Run Code Online (Sandbox Code Playgroud)

当我的默认 shell 是 bash shell 时,这曾经工作得很好。我在这里所做的就是将一些文件夹添加到我将在 shell 脚本中使用的数组变量中。发布升级并将我的默认 shell 设置为 zsh,启动脚本时出现以下错误(通过 .zsrc 文件中的别名)

[ayusman@~10:39AM]$updateExpediaGitRepos 
/Users/ayusman/scripts/updateGitRepos.sh:250: ROOT: assignment to invalid subscript range
[ayusman@~10:39AM]$
Run Code Online (Sandbox Code Playgroud)

我验证了当我将 shell 更改回 bash(通过执行如下所示的 chsh)时,相同的脚本按预期运行。

chsh -s /bin/bash
Run Code Online (Sandbox Code Playgroud)

所以本质上问题是我是否可以不使用现有的 bash 脚本并从 zsh shell 运行?

谢谢,阿尤斯曼

Sté*_*las 5

听起来您是在要求zsh解释该脚本。你没有说updateExpediaGitRepos是什么,但我想使用or内置命令alias 来获取该脚本。这些命令告诉当前 shell 解释器解释文件中的代码,因此 shebang ( ) 不相关。shebang 仅在您尝试执行脚本时由内核使用。.source#! /bin/bash

据推测,它updateGitRepos.sh用于通过修改用户 shell 的属性(如设置环境变量、定义函数、别名...)来自定义用户环境,在这种情况下执行它不会有帮助。

bashzsh两种不同且不兼容的语言的解释器(尽管它们有一些共同点,因为它们都从 Bourne shell、Korn shell 和 C shell 中汲取了很多灵感)。通常不能指望一个人能够解释为另一个人编写的代码。

特别是,数组的实现非常不同。

zsh数组实际上是数组,其索引从 1 开始,就像大多数其他 shell 和通常在 shell 中使用的工具一样(更多信息请参见Is there a Reason Why the first element of a Zsh array is indexed by 1而不是 0?)。

bash数组是从 Korn shell 复制的。它们是稀疏数组(更像是键仅限于正整数的关联数组)并且索引从 0 开始。

zsh支持多种仿真,可用于解释为其他 shell 编写的代码。特别是,它有一个 ksh 模拟模式,对于使用数组解析脚本非常有用bash

emulate ksh
Run Code Online (Sandbox Code Playgroud)

开始它。

或者:

emulate ksh -c 'some code'
Run Code Online (Sandbox Code Playgroud)

在该仿真模式下评估代码。在该模式下声明的函数继承模拟模式。

除此之外,在ksh仿真模式下,该KSH_ARRAYS选项被打开,这使得数组索引从 0 开始(但仍然不稀疏)。

因此,在这里,您可以尝试修改您的别名,以便它可以:

emulate ksh -c '. /Users/ayusman/scripts/updateGitRepos.sh'
Run Code Online (Sandbox Code Playgroud)

代替

. /Users/ayusman/scripts/updateGitRepos.sh
Run Code Online (Sandbox Code Playgroud)

对于您的情况来说,这可能足够,也可能不够。该模拟模式仅提高了与 的兼容性ksh,它不会使 zsh 成为 ksh 克隆。而且 ksh 不是 bash。

如果updateGitRepos.sh确实要源到用户的 shell 中,那么您应该为每个受支持的 shell 提供不同版本的脚本,每个脚本都用相应的语言编写,或者使用与所有受支持的 shell 兼容的语法,这通常会排除数组(但请参阅测试 shell 对数组的支持以了解可能的方法)。

如果该脚本只是要执行,而不是由用户的交互式 shell 解释,那么请确保执行它,这要/path/to/the/script感谢 shebang 将确保启动正确的解释器来解释它, not source /path/to/the/script, not zsh /path/to/the/script(bash /path/to/the/script也可以工作在这里,因为它是一个bash脚本(尽管有误导性的.sh扩展名))。