Я довольно новичок в 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-)