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 +387
vim en lugar de abrir un archivo ./manifests/production/test.pp
con el nombre +387
adjunto. 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 $variable
significa “tomar el valor de la variable, dividirlo en palabras separadas donde IFS
aparecen 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 variable
es una matriz, esto le sucede al primer elemento de la matriz y los demás elementos se ignoran.
En zsh, la sintaxis $variable
significa "tomar el valor de la variable, excepto eliminarlo si está vacío". Si variable
es 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 $=variable
para 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 $=variable
en 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-)