¿Cuál es la forma correcta/mejor de manejar espacios y comillas en la finalización de bash?Manejar los espacios y las comillas correctamente en la finalización de bash
Aquí hay un ejemplo simple. Tengo un comando llamado words
(por ejemplo, un programa de búsqueda de diccionario) que toma varias palabras como argumentos. Las 'palabras' apoyados en realidad pueden contener espacios, y se define en un archivo llamado words.dat
:
foo
bar one
bar two
Aquí está mi primera solución sugerida:
_find_words()
{
search="$cur"
grep -- "^$search" words.dat
}
_words_complete()
{
local IFS=$'\n'
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(compgen -W "$(_find_words)" -- "$cur"))
}
complete -F _words_complete words
Typing ‘words f<tab>’
completa correctamente el comando para ‘words foo ’
(con una espacio final), que es bueno, pero para ‘words b<tab>’
sugiere ‘words bar ’
. La finalización correcta sería ‘words bar\ ’
. Y para ‘words "b<tab>’
y ‘words 'b<tab>’
no ofrece sugerencias.
Esta última parte que he podido resolver. Es posible usar eval
para analizar correctamente los caracteres (escapados). Sin embargo, eval
no es aficionado a las frases que faltan, así que para obtener todo funcione, he tenido que cambiar el search="$cur"
a
search=$(eval echo "$cur" 2>/dev/null ||
eval echo "$cur'" 2>/dev/null ||
eval echo "$cur\"" 2>/dev/null || "")
Esto funciona en realidad. Ambos ‘words "b<tab>’
y ‘words 'b<tab>’
se autocompletan correctamente, y si agrego un ‘o’
y presiono <tab>
nuevamente, en realidad completa la palabra y agrega la cita de cierre correcta. Sin embargo, si intento completar ‘words b<tab>’
o incluso ‘words bar\ <tab>’
, se autocompleta a ‘words bar ’
en lugar de ‘words bar\ ’
, y al agregar, por ejemplo, ‘one’
, se produce un error cuando se ejecuta el programa words
.
Ahora, obviamente es es posible manejar esto correctamente. Por ejemplo, el comando ls
puede hacerlo para los archivos námned ‘foo’
‘bar one’
y ‘bar two’
(aunque tiene problemas con algunas formas de expresar los nombres de archivo cuando se usa una combinación (válida) de "
, '
y varios escapes). Sin embargo, no pude entender cómo lo hace ls
leyendo el código de finalización de bash.
Entonces, ¿alguien sabe cómo manejar esto correctamente? Las cotizaciones de entrada reales no necesitan conservarse; Estaría contento con una solución que cambia ‘words "b<tab>’
, ‘words 'b<tab>’
y ‘words b<tab>’
a ‘words bar\ ’
, por ejemplo, (aunque preferiría omitir las comillas, como en este ejemplo, en lugar de agregarlas).
Gracias. Esta solución funciona para los ejemplos originales, pero si agrego 'rock' n roll 'a words.dat, falla. Mi uso de la autocompletación en la vida real en realidad involucra palabras con apóstrofes, y esa es la razón por la que originalmente usé 'eval'. Es bastante fácil (aunque no muy elegante) corregir, agregando un "buscar y reemplazar" extra al 'for loop, y luego agregar otro ciclo for para cadenas que comiencen con '. El único problema restante, hasta donde puedo ver, es que la autocompletación no avanza una posición del cursor si ha escrito una palabra completa, incluidas las comillas de cierre. –
Con respecto a mi comentario anterior. Parece que la situación es un poco peor de lo que pensaba. La finalización automática dentro de una palabra que contiene apóstrofes (por ejemplo, intentar autocompletar 'rock' n ro ', ya sea utilizando espacios escabrosos y apóstrofo, o comillas simples o dobles) no funciona. La razón es que la variable 'search' no está en su forma expandida correcta. Algunas sustituciones adicionales parecen posibles, pero no he podido hacer que esto funcione correctamente para las tres formas diferentes de escapar. –
Sí, compgen parece estar eliminando todos los qoutes ... lo que significa que deben escaparse dentro de _find_words – Eugene