Zsh possivelmente adicionando aspas ao valor da variável (embora funcione no bash)

Zsh possivelmente adicionando aspas ao valor da variável (embora funcione no bash)

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 +387no vim em vez de abrir um arquivo nomeado ./manifests/production/test.ppanexado +387a 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 $variablesignifica “pegar o valor da variável, dividi-lo em palavras separadas onde os caracteres IFSaparecem e tratar cada palavra como um padrão curinga de nome de arquivo e expanda-o se corresponder a um ou mais arquivos”. Se variablefor um array, isso acontece com o primeiro elemento do array e os outros elementos são ignorados.

No zsh, a sintaxe $variablesignifica “pegar o valor da variável, exceto removê-lo se estiver vazio”. Se variablefor um array, isso acontece com todos os elementos do array. Os entusiastas do Zsh consideram o zsh muito superior.

No zsh, você pode escrever $=variablepara 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 $=variableem 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-)

informação relacionada