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

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

更新 通过这个看关联,我更新了数组下标以 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.

但我开始在其他地方看到错误,因为我之前声明的 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.

当我的默认 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]$

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

chsh -s /bin/bash

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

谢谢,阿尤斯曼

答案1

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

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

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

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

zsh数组实际上是数组,其索引从 1 开始,就像大多数其他 shell 和通常在 shell 中使用的工具一样(更多信息请参见Zsh 数组的第一个元素索引为 1 而不是 0 是否有原因?)。

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

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

emulate ksh

开始它。

或者:

emulate ksh -c 'some code'

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

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

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

emulate ksh -c '. /Users/ayusman/scripts/updateGitRepos.sh'

代替

. /Users/ayusman/scripts/updateGitRepos.sh

对于您的情况来说,这可能足够,也可能不够。仅该模拟模式改善与 的兼容性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扩展名))。

答案2

该行为是由于数组在zshshell 中的工作方式决定的,它们的索引从 和1开始不是0。因此,对索引处元素的任何访问0都会引发您所看到的错误。

zsh手册中 -15.2.1 数组下标

15.2.1 Array Subscripts

可以使用下标来选择数组的各个元素。形式的下标[exp]选择单个元素exp,其中exp是一个算术表达式,它将进行算术扩展,就好像它被包围一样$((...))。元素的编号开头为1,除非KSH_ARRAYS设置了该选项,在这种情况下它们从零开始编号

如果KSH_ARRAYS未设置该选项,则默认访问具有下标的数组元素计算为零返回空字符串, 尽管尝试写入此类元素将被视为错误。为了向后兼容,KSH_ZERO_SUBSCRIPT可以设置该选项以使下标值 0 和 1 相等;请参阅选项说明中的选项说明。

因此,要模拟以 index 开头的数组的行为0,请在脚本顶部设置此选项

setopt ksh_arrays

为了澄清为什么脚本会表现出zsh行为,即使 she-bang 解释器设置为#!/bin/bash.该脚本可能是通过显式调用运行的,zsh <script>在这种情况下,操作系统无法识别脚本顶部的解释器行。一旦脚本本身成为可执行文件 ( chmod +x) 并使用 运行./<script>,脚本顶部提供的解释器将受到尊重。

相关内容