tutorial - Personalización de la salida de finalización de bash: cada sugerencia en una nueva línea
microsoft visual studio descargar (2)
Cuando escribe algo, a menudo usa el autocompletado de bash: comienza a escribir un comando, por ejemplo, y escribe TAB
para obtener el resto de la palabra.
Como probablemente habrá notado, cuando múltiples opciones coinciden con su comando, bash las muestra así:
foobar@myserv:~$ admin-
admin-addrsync admin-adduser admin-delrsync admin-deluser admin-listsvn
admin-addsvn admin-chmod admin-delsvn admin-listrsync
Estoy buscando una solución para mostrar cada solución posible en una nueva línea, similar a la última columna en un ls -l
. Mejor aún, sería perfecto si pudiera aplicar una regla como esta: "si encuentra menos de 10 sugerencias, muéstrelas una por línea, si es más => pantalla real" .
bash
4.2+ (y, más generalmente, las aplicaciones que utilizan readline
6.2+) lo admiten con el uso de la variable de completion-display-width
.
El número de columnas de pantalla utilizadas para mostrar posibles coincidencias al realizar la finalización. El valor se ignora si es menor que 0 o mayor que el ancho de la pantalla del terminal. Un valor de 0 hará que las coincidencias se muestren una por línea. El valor predeterminado es -1.
Ejecute lo siguiente para establecer el comportamiento de todas las completaciones 1 para su sesión actual:
bind ''set completion-display-width 0''
O modifique su archivo ~/.inputrc
2 para que tenga:
set completion-display-width 0
Para cambiar el comportamiento de todas las nuevas conchas.
1 Vea aquí un método para controlar este comportamiento para funciones de finalización personalizadas individuales.
2 La ruta de búsqueda para el archivo de inicio readline es $INPUTRC
, ~/.inputrc
, /etc/inputrc
así que modifique el archivo apropiado para usted.
bash
antes de la versión 4.2 no permite ningún control sobre el formato de salida de las terminaciones , desafortunadamente.
Bash 4.2+ permite cambiar globalmente a 1 sugerencia por línea, como se explica en la útil respuesta de Grisha Levit , que también se enlaza con una solución inteligente para lograr una solución de función por finalización .
La siguiente es una solución compleja para una finalización personalizada . Resolver este problema de forma genérica , para todas las terminaciones definidas, sería mucho más difícil (si hubiera una manera de invocar directamente las funciones de línea de readline
, podría ser más fácil, pero no he encontrado una manera de hacerlo).
Para probar la prueba de concepto a continuación:
- Guárdelo en un archivo y guárdelo (
. file
) En su shell interactivo. Esto:- define un comando llamado
foo
(una función de shell) - cuyos argumentos se completan según los nombres de archivo coincidentes en el directorio actual.
- (Cuando se invoca
foo
, simplemente imprime su argumento en forma de diagnóstico).
- define un comando llamado
- Invoque como:
foo [fileNamePrefix]
, luego presione tab :- Si entre 2 y 9 archivos en el directorio actual coinciden, verá la visualización línea por línea deseada.
- De lo contrario (1 partida o 10 o más coincidencias), se producirá la finalización normal.
Limitaciones :
- La finalización solo funciona correctamente cuando se aplica al último argumento en la línea de comando que se está editando.
- Cuando realmente se inserta una terminación en la línea de comando (una vez que la coincidencia no es ambigua), NO se le agrega ningún espacio (este comportamiento es necesario para la solución).
- Es posible que no se pueda volver a dibujar la solicitud la primera vez después de imprimir una salida con formato personalizado: se debe simular la línea de comando, incluida la solicitud, y como no hay una forma directa de obtener una versión ampliada de la cadena de definición de la solicitud almacenada en
$PS1
, Se utiliza una solución alternativa (inspirada en https://.com/a/24006864/45375 ), que debería funcionar en casos típicos , pero no es infalible.
Enfoque
- Define y asigna una función de shell de finalización personalizada al comando de interés.
- La función personalizada determina las coincidencias y, si su recuento se encuentra en el rango deseado, omite el mecanismo de finalización normal y crea una salida con formato personalizado.
- La salida con formato personalizado (cada coincidencia en su propia línea) se envía directamente al terminal
>/dev/tty
, y luego el indicador y la línea de comando se "vuelven a dibujar" manualmente para imitar el comportamiento de finalización estándar. - Vea los comentarios en el código fuente para detalles de implementación.
# Define the command (function) for which to establish custom command completion.
# The command simply prints out all its arguments in diagnostic form.
foo() { local a i=0; for a; do echo "/$$((i+=1))=[$a]"; done; }
# Define the completion function that will generate the set of completions
# when <tab> is pressed.
# CAVEAT:
# Only works properly if <tab> is pressed at the END of the command line,
# i.e., if completion is applied to the LAST argument.
_complete_foo() {
local currToken="${COMP_WORDS[COMP_CWORD]}" matches matchCount
# Collect matches, providing the current command-line token as input.
IFS=$''/n'' read -d '''' -ra matches <<<"$(compgen -A file "$currToken")"
# Count matches.
matchCount=${#matches[@]}
# Output in custom format, depending on the number of matches.
if (( matchCount > 1 && matchCount < 10 )); then
# Output matches in CUSTOM format:
# print the matches line by line, directly to the terminal.
printf ''/n%s'' "${matches[@]}" >/dev/tty
# !! We actually *must* pass out the current token as the result,
# !! as it will otherwise be *removed* from the redrawn line,
# !! even though $COMP_LINE *includes* that token.
# !! Also, by passing out a nonempty result, we avoid the bell
# !! signal that normally indicates a failed completion.
# !! However, by passing out a single result, a *space* will
# !! be appended to the last token - unless the compspec
# !! (mapping established via `complete`) was defined with
# !! `-o nospace`.
COMPREPLY=( "$currToken" )
# Finally, simulate redrawing the command line.
# Obtain an *expanded version* of `$PS1` using a trick
# inspired by https://.com/a/24006864/45375.
# !! This is NOT foolproof, but hopefully works in most cases.
expandedPrompt=$(PS1="$PS1" debian_chroot="$debian_chroot" "$BASH" --norc -i </dev/null 2>&1 | sed -n ''${s/^/(.*/)exit$//1/p;}'')
printf ''/n%s%s'' "$expandedPrompt" "$COMP_LINE" >/dev/tty
else # Just 1 match or 10 or more matches?
# Perform NORMAL completion: let bash handle it by
# reporting matches via array variable `$COMPREPLY`.
COMPREPLY=( "${matches[@]}" )
fi
}
# Map the completion function (`_complete_foo`) to the command (`foo`).
# `-o nospace` ensures that no space is appended after a completion,
# which is needed for our workaround.
complete -o nospace -F _complete_foo -- foo