Zsh 可能会为变量值添加引号(但在 bash 中也可以)

Zsh 可能会为变量值添加引号(但在 bash 中也可以)

我对 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-)

相关内容