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 не работает так, как ожидалось. Она открывает файл с именем ./manifests/production/test.pp +387в vim вместо того, чтобы открыть файл с именем ./manifests/production/test.pp, +387к которому добавлено. Похоже, она добавляет кавычки к $cmd.

Было бы здорово, если бы кто-нибудь объяснил, что здесь происходит. Спасибо.

решение1

В обычных оболочках в стиле Bourne, таких как 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 editing-fu 8-)

Связанный контент