Zsh 可能为变量值添加引号(尽管在 bash 中有效)

Abh*_*ogi 3 zsh quoting

我对 zsh 还很陌生(昨天从 bash 转移了)

我在 bash 中有一个 bash 函数,比如

vl() { cmd=`echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'`; vim $cmd }
Run Code Online (Sandbox Code Playgroud)

这基本上转换了一个参数,如:

vl ./manifests/production/test.pp:387:foobar  # A output of $grep -iHn test 
Run Code Online (Sandbox Code Playgroud)

vim ./manifests/production/test.pp +387   #Aim is to open file at line-number 387
Run Code Online (Sandbox Code Playgroud)

zsh 中的相同功能无法按预期工作。它打开一个以./manifests/production/test.pp +387vim命名的文件,而不是打开一个名为./manifests/production/test.pp+387附加到它。似乎,它将引号添加到$cmd.

如果有人解释这里发生的事情,那就太好了。谢谢

Gil*_*il' 6

在 Bourne shell、dash、ksh 和 bash 等普通 Bourne 风格的 shell 中,语法的$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 "$@"
}
Run Code Online (Sandbox Code Playgroud)