【发布时间】:2020-06-19 03:03:41
【问题描述】:
原标题: 脚本来源时间接参数替换中断(zsh)
zsh 5.7.1 (x86_64-apple-darwin19.0)
GNU bash,版本 4.4.20(1)-release (x86_64-pc-linux-gnu)
我正在 Mac 上开发一个 shell 脚本,并试图让它在 bash 和 zsh 之间保持可移植性,因此数组索引是一个考虑因素。我知道我可以将 KSH_ARRAYS 设置为从 0 开始索引,但我决定在操作系统中查询正在使用的 shell 并相应地设置开始索引,这导致了下面描述的问题。
使用间接扩展是有道理的(无论如何对我来说!),这就是导致问题的原因。考虑脚本indirect.sh:
#! /bin/bash
declare -r ARRAY_START_BASH=0
declare -r ARRAY_START_ZSH=1
declare -r SHELL_BASH=0
declare -r SHELL_ZSH=1
# Indirect expansion is used to reference the values of the variables declared
# in this case statement e.g. ${!ARRAY_START}
case $(basename $SHELL) in
"bash" )
declare -r SHELL_ID=SHELL_BASH
declare -r ARRAY_START=ARRAY_START_BASH
;;
"zsh" )
declare -r SHELL_ID=SHELL_ZSH
declare -r ARRAY_START=ARRAY_START_ZSH
;;
* )
return 1
;;
esac
echo "Shell ID: ${!SHELL_ID} Index arrays from: ${!ARRAY_START}"
在同一目录中从命令行运行时效果很好:
<my home> ~ % echo "$(./indirect.sh)"
Shell ID: 1 Index arrays from: 1
当我获取脚本时出现问题:
<my home> ~ % echo "$(. ~/indirect.sh)"
/Users/<me>/indirect.sh:28: bad substitution
我不明白为什么采购脚本会改变参数扩展的行为。
这是预期的行为吗?如果是这样,我将不胜感激,如果有人可以解释它并希望提供解决方法。
【问题讨论】:
-
如果你从命令行输入脚本名来运行它,它是由 bash 执行的,但是当你从你的 zsh 中获取它时,它是由 zsh 执行的。通常,您不会期望程序在解释为不同语言时产生相同的结果。另请注意,查询
SHELL的值并不能可靠地告诉您正在运行的 shell。例如,当我在 Mac 上运行 zsh 时,SHELL 设置为 bash。无论如何,在你的脚本中添加一个set -x,这样你就可以看到出错的地方和原因。 -
zsh使用与bash不同的语法进行间接参数扩展。:${(P)SHELL_ID}。 -
执行脚本时使用shebang。当你使用
.时,使用当前的shell (zsh),忽略shebang。 -
您有两个问题:1) 通常,您无法编写在
bash和zsh中同样工作的脚本,除非您坚持符合POSIX 的功能。 2) 一般来说,您不应该尝试编写可以执行或获取的脚本。您通常会获取一个文件,因为它需要影响调用者的环境,而执行脚本不能这样做。 -
@chepner:当然,shebang。如果不是一直浪费时间,那会很有趣!文档中指出了用于间接扩展的 zsh 语法。以为我看过那里,但显然我没有。当然,问题更为根本。我不太确定发布答案的协议,所以我自己回答了。如果有错误请告诉我,我会编辑。
标签: bash zsh parameter-expansion