Zsh posiblemente agregue comillas al valor de la variable (aunque funciona en bash)

Zsh posiblemente agregue comillas al valor de la variable (aunque funciona en bash)

Soy bastante nuevo en zsh (cambié ayer de bash)

Tenía una función bash en bash como

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

Básicamente, esto convierte un argumento como:

vl ./manifests/production/test.pp:387:foobar  # A output of $grep -iHn test 

a

vim ./manifests/production/test.pp +387   #Aim is to open file at line-number 387

La misma función en zsh no funciona como se esperaba. Abre un archivo con el nombre ./manifests/production/test.pp +387vim en lugar de abrir un archivo ./manifests/production/test.ppcon el nombre +387adjunto. Parece que está agregando las comillas a $cmd.

Sería genial si alguien explicara lo que está pasando aquí. Gracias

Respuesta1

En shells normales de estilo Bourne, como Bourne Shell, dash, ksh y bash, la sintaxis $variablesignifica “tomar el valor de la variable, dividirlo en palabras separadas donde IFSaparecen los caracteres y tratar cada palabra como un patrón comodín de nombre de archivo y expandirlo si coincide con uno o más archivos”. Si variablees una matriz, esto le sucede al primer elemento de la matriz y los demás elementos se ignoran.

En zsh, la sintaxis $variablesignifica "tomar el valor de la variable, excepto eliminarlo si está vacío". Si variablees una matriz, esto les sucede a todos los elementos de la matriz. Los entusiastas de Zsh consideran que la forma zsh es superior.

En zsh, puedes escribir $=variablepara realizar la división de palabras. Sin embargo, esta no es la mejor manera de hacer lo que estás haciendo. Su función bash no admite espacios en blanco en los nombres de archivos, y su uso $=variableen zsh tampoco lo haría. Aquí hay una forma diferente de analizar el argumento que funciona tanto en bash como en zsh y hace frente a cualquier carácter excepto :en un nombre de archivo. Si el argumento contiene dos dos puntos, todo lo que está después de los primeros dos puntos se elimina y la parte entre los primeros dos puntos y los segundos dos puntos se agrega como un argumento separado precedido por un +signo. Es un poco más largo que su código, pero menos difícil de entender y no se bloquea ante el primer indicio de un espacio en el nombre de un archivo.

vl () {
  local suffix
  case $1 in
    *:*:*) suffix=${1#*:};; set -- "${1%%:*}" "+${suffix%%:*}";;
  esac
  vim "$@"
}

Respuesta2

Es complicado :) Una solución es definir la función de esta manera:

vl() { cmd=$(echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'); eval "vim $cmd"; }

Tenga en cuenta que la solución es el uso de eval, no las otras modificaciones menores que tuve que hacer porque me falta la edición de stackexchange requerida-fu 8-)

información relacionada