通过变量存储绝对路径执行fzf:Bash正常但Zsh报错的跨Shell兼容问题排查
通过变量存储绝对路径执行fzf:Bash正常但Zsh报错的跨Shell兼容问题排查
嗨,你遇到的这个问题其实是Bash和Zsh里type命令的行为差异搞出来的!
先看你的报错信息:fun:4: no such file or directory: fzf is /home/rishi/commandline-plugins/fzf/bin/fzf,这里已经很明显了——Zsh里执行type -p fzf的时候,输出的不是单纯的绝对路径,而是带说明的整句话fzf is /home/.../fzf,你把这个整串赋值给fzf_cmd之后,执行的时候系统会把整句话当成命令路径,当然找不到对应的文件啦!
而Bash里的type -P(注意是大写P)确实只会输出命令的绝对路径,所以在Bash里能正常运行。
下面给你几个解决办法,都能实现跨Shell兼容:
方法1:修正Zsh的type命令参数
Zsh里的type命令可以加-f参数来强制只输出纯路径,和Bash的type -P行为对齐。修改后的脚本如下:
fun() { local fzf_cmd if [[ -n "${BASH_VERSION}" ]]; then fzf_cmd="$(type -P fzf)" elif [[ -n "${ZSH_VERSION}" ]]; then fzf_cmd="$(type -pf fzf)" fi "${fzf_cmd}" --height 40% } fun
这里Zsh用type -pf,就能拿到和Bashtype -P一样的纯路径结果了。
方法2:用跨Shell兼容的command -v命令
command -v是POSIX标准命令,在Bash和Zsh里的行为完全一致,都会输出外部命令的绝对路径(如果是外部命令的话),用它可以简化脚本,不用再区分不同Shell:
fun() { local fzf_cmd fzf_cmd="$(command -v fzf)" "${fzf_cmd}" --height 40% } fun
这个方案更简洁,也是我更推荐的方式,毕竟少写分支逻辑,出错概率更低。
方法3:更健壮的版本(加存在性校验)
如果担心fzf可能没安装,或者路径不可执行,可以再加一层校验,让脚本更健壮:
fun() { local fzf_cmd fzf_cmd="$(command -v fzf)" if [[ -x "${fzf_cmd}" ]]; then "${fzf_cmd}" --height 40% else echo "错误:fzf未找到或不可执行" >&2 return 1 fi } fun
这样就算fzf没装,脚本也会给出清晰的错误提示,而不是直接崩溃。
备注:内容来源于stack exchange,提问作者Rishi K.
相关产品推荐
相关产品推荐

