我对 zsh 相当陌生(昨天从 bash 转移)
我在 bash 中有一个 bash 函数,比如
vl() { cmd=`echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'`; vim $cmd }
这基本上转换了一个参数,如:
vl ./manifests/production/test.pp:387:foobar # A output of $grep -iHn test
到
vim ./manifests/production/test.pp +387 #Aim is to open file at line-number 387
zsh 中的相同功能无法按预期工作。它打开一个在 vim 中命名的文件./manifests/production/test.pp +387
,而不是打开一个附加在其后面的./manifests/production/test.pp
名为的文件。+387
看起来,它正在将引号添加到$cmd
.
如果有人解释这里发生了什么,那就太好了。谢谢
答案1
在普通的 Bourne 风格 shell 中,例如 Bourne shell、dash、ksh 和 bash,语法的$variable
意思是“获取变量的值,将其拆分为IFS
出现字符的单独单词,并将每个单词视为文件名通配符模式,并且如果它与多个文件之一匹配,则展开它”。如果variable
是一个数组,则这种情况发生在数组的第一个元素上,而其他元素将被忽略。
在 zsh 中,语法的$variable
意思是“获取变量的值,如果它为空则将其删除”。如果variable
是一个数组,则该数组的所有元素都会发生这种情况。 Zsh 爱好者认为 zsh 方式更优越。
在 zsh 中,您可以编写$=variable
来执行分词。不过,这并不是做你正在做的事情的最佳方式。您的 bash 函数无法处理文件名中的空格,并且$=variable
在 zsh 中使用也不会。这是一种不同的解析参数的方法,它适用于 bash 和 zsh,并且可以处理除:
文件名之外的任何字符。如果参数包含两个冒号,则删除第一个冒号之后的所有内容,并将第一个冒号和第二个冒号之间的部分作为单独的参数附加,前面加一个+
符号。它比您的代码稍长,但不那么难以理解,而且它不会因为文件名中的第一个空格提示而感到窒息。
vl () {
local suffix
case $1 in
*:*:*) suffix=${1#*:};; set -- "${1%%:*}" "+${suffix%%:*}";;
esac
vim "$@"
}
答案2
这是一个棘手的问题:) 一种解决方法是像这样定义函数:
vl() { cmd=$(echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'); eval "vim $cmd"; }
请注意,解决方法是使用eval
,而不是我必须做的其他小修改,因为我缺少所需的 stackexchange editor-fu 8-)