Sou bastante novo no zsh (mudou ontem do bash)
Eu tinha uma função bash no bash como
vl() { cmd=`echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'`; vim $cmd }
Isso basicamente converte um argumento como:
vl ./manifests/production/test.pp:387:foobar # A output of $grep -iHn test
para
vim ./manifests/production/test.pp +387 #Aim is to open file at line-number 387
A mesma função no zsh não funciona conforme o esperado. Ele abre um arquivo nomeado ./manifests/production/test.pp +387
no vim em vez de abrir um arquivo nomeado ./manifests/production/test.pp
anexado +387
a ele. Parece que está adicionando aspas a $cmd
.
Seria ótimo se alguém explicasse o que está acontecendo aqui. Obrigado
Responder1
Em shells normais do estilo Bourne, como Bourne Shell, dash, ksh e bash, a sintaxe $variable
significa “pegar o valor da variável, dividi-lo em palavras separadas onde os caracteres IFS
aparecem e tratar cada palavra como um padrão curinga de nome de arquivo e expanda-o se corresponder a um ou mais arquivos”. Se variable
for um array, isso acontece com o primeiro elemento do array e os outros elementos são ignorados.
No zsh, a sintaxe $variable
significa “pegar o valor da variável, exceto removê-lo se estiver vazio”. Se variable
for um array, isso acontece com todos os elementos do array. Os entusiastas do Zsh consideram o zsh muito superior.
No zsh, você pode escrever $=variable
para realizar a divisão de palavras. Esta não é a melhor maneira de fazer o que você está fazendo. Sua função bash não lida com espaços em branco em nomes de arquivos, e usar $=variable
em zsh também não. Aqui está uma maneira diferente de analisar o argumento que funciona tanto no bash quanto no zsh e lida com qualquer caractere, exceto :
no nome de um arquivo. Se o argumento contiver dois dois pontos, tudo após o primeiro dois pontos será removido e a parte entre o primeiro e o segundo dois pontos será anexada como um argumento separado precedido por um +
sinal. É um pouco mais longo que o seu código, mas menos difícil de entender e não engasga com a primeira sugestão de espaço no nome de um arquivo.
vl () {
local suffix
case $1 in
*:*:*) suffix=${1#*:};; set -- "${1%%:*}" "+${suffix%%:*}";;
esac
vim "$@"
}
Responder2
É complicado :) Uma solução alternativa é definir a função assim:
vl() { cmd=$(echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'); eval "vim $cmd"; }
Observe que a solução alternativa é o uso de eval
, não as outras pequenas modificações que tive que fazer porque não tenho o stackexchange edit-fu necessário 8-)