![从 zsh 运行时,Bash 脚本抛出“分配给无效下标范围”](https://linux22.com/image/166026/%E4%BB%8E%20zsh%20%E8%BF%90%E8%A1%8C%E6%97%B6%EF%BC%8CBash%20%E8%84%9A%E6%9C%AC%E6%8A%9B%E5%87%BA%E2%80%9C%E5%88%86%E9%85%8D%E7%BB%99%E6%97%A0%E6%95%88%E4%B8%8B%E6%A0%87%E8%8C%83%E5%9B%B4%E2%80%9D.png)
更新 通过这个看关联,我更新了数组下标以 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 的属性(如设置环境变量、定义函数、别名...)来自定义用户环境,在这种情况下执行它不会有帮助。
bash
是zsh
两种不同且不兼容的语言的解释器(尽管它们有一些共同点,因为它们都从 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 , not source /path/to/the/script
(zsh /path/to/the/script
bash /path/to/the/script
也可以工作在这里,因为它是一个bash
脚本(尽管有误导性的.sh
扩展名))。
答案2
该行为是由于数组在zsh
shell 中的工作方式决定的,它们的索引从 和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>
,脚本顶部提供的解释器将受到尊重。