我有一个源自.bashrc并.zshrc包含一些函数的文件。以前它是两个单独的文件(对于每个 shell),但我现在使用单个文件,因为这些文件几乎相同,并且我更容易管理单个函数文件。
有一个函数对于两个 shell 来说是不同的,所以我想我可以使用一个条件语句,以便使用正确的语句:
[[ $BASH_VERSION ]] && shell=bash
[[ $ZSH_VERSION ]] && shell=zsh
# Search man page for string
if [[ $shell == bash ]]; then
mans() {
local q="\'"
local q_pattern="'${1//$q/$q\\$q$q}'"
local MANPAGER="less -+MFX -p $q_pattern"
man "$2"
}
elif [[ $shell == zsh ]]; then
mans() MANPAGER="less -+MFX -p ${(q+)1}" man $2
fi
Run Code Online (Sandbox Code Playgroud)
这似乎在 zsh 中工作正常,但是当切换到 bash 时,我从 zsh 行收到错误,即使它不应该在 bash 中使用。有什么办法可以阻止它解析该行吗?
Sté*_*las 12
您可以定义一些ifbash, ifzsh,endif别名,例如:
alias if{ba,z}sh=':||:<<"endif"' endif=\nif [[ -n $BASH_VERSION ]]; then\n alias ifbash=\n shopt -s expand_aliases\nelif [[ -n $ZSH_VERSION ]]; then\n alias ifzsh=\nfi\n\nifbash\nf() { echo bash; }\nendif\n\nifzsh\nf() echo ${(q+):-zsh}\nendif\nRun Code Online (Sandbox Code Playgroud)\n:||:<<"MARKER"...MARKER是注释掉一段代码的惯用方法。这就像在 stdin 上使用 here-doc:<<"MARKER"运行:noop 内置函数,但是使用 extra 时:||,第二个:不会运行,并且 here-document 甚至没有创建,只是被解析掉。
请注意,endif不得缩进,也不得在其后添加任何内容;它必须构成整条线。ifbash/ ifzshs 不能嵌套(无论如何这里都没有意义)。
顺便说一句,man似乎是在环境变量中单独进行引号解析MANPAGER(而不是调用 shell,更不用说您的了$SHELL)并且似乎不支持$'...'引号的形式,因此使用q+可能使用该形式的参数扩展标志某些字符串的引号不正确。使用qq相反,它使用单引号(并\\'在引号之外转义单引号\xc2\xb9),就像在 bash 版本中一样。
\xc2\xb9 除非rcquotes启用该选项,在这种情况下将使用''\xc3\xa0 larc代替。在函数的开头添加emulate -L zsh,在该函数中拥有一组合理的本地选项不会有帮助,因为需要在定义函数时禁用该选项,而不是运行函数。
Bash 仍然必须解析整个文件,即使它不会执行每一行。您通常无法将语法错误隐藏在条件后面,只能隐藏运行时错误。
代替你,我会继续使用单独的.zshrcand .bashrc。然后,我将通用函数放在第三个文件中(确保该文件仅使用与两者兼容的语法),并从 和 获取.zshrc它.bashrc。
在我看来,这是世界上最好的:
.zshrcbash 永远不会读取的位置。同样,仅 bash 的内容也存在于.bashrc.任何 shell 都必须解析条件中的代码以找到条件结束的部分,即使没有其他原因。
除了将特定于 shell 的代码放入另一个文件或 to 的字符串中之外eval,您还可以使用here-doc 来source直接隐藏它和here-doc。与 using 几乎相同eval,但 here-doc 的优点是内部代码可以包含单引号和双引号,而不会出现任何烦人的转义问题。
例如,此脚本表示hello, 'bar', I'm zsh如果使用 zsh 运行,并在 Bash 中抛出错误:
if [[ -n $ZSH_VERSION ]]; then
source /dev/stdin <<'EOF'
foo() {
echo "hello, '$1', I'm zsh"
}
EOF
fi
foo bar
Run Code Online (Sandbox Code Playgroud)
不过,我不确定是否source /dev/stdin适用于所有 shell 和系统。(是的,source这是内置命令的非标准名称.,但它应该在 Bash 和 zsh 中工作,并且无论如何该命令只需要存在于运行条件内部的 shell 中。)
其他人已经指出了为什么 bash 从语法上解析条件的内容$shell == zsh。
在 zsh 上你可以使用
mans() MANPAGER="less -+MFX -p ${(q+)1}" man $2
Run Code Online (Sandbox Code Playgroud)
而这不是合法的 bash 语法(函数需要 {})。
但是,在 zsh 上,您还可以对函数使用 POSIX 语法,这将使两个 shell 都满意:
elif [[ $shell == zsh ]]; then
mans() {
MANPAGER="less -+MFX -p ${(q+)1}" man $2
}
fi
Run Code Online (Sandbox Code Playgroud)
此外,我通常会将它们更改[[为单一语法,这样如果在不支持的[其他 shell(例如 )上运行,文件就不会中断:dash[[
[ -n "$BASH_VERSION" ] && shell=bash
[ -n "$ZSH_VERSION" ] && shell=zsh
# Search man page for string
if [ "$shell" = bash ]; then
mans() {
local q="\'"
local q_pattern="'${1//$q/$q\\$q$q}'"
local MANPAGER="less -+MFX -p $q_pattern"
man "$2"
}
elif [ "$shell" = zsh ]; then
mans() {
MANPAGER="less -+MFX -p ${(q+)1}" man $2
}
fi
Run Code Online (Sandbox Code Playgroud)