Estoy trabajando con una gran cantidad de archivos, que guardo en un directorio. Cada vez que entro a ese directorio y accidentalmente presiono Tabdos veces, se tarda demasiado (puede ser más de un minuto) en mostrar los archivos que coinciden con el patrón, y estoy bastante molesto con este comportamiento.
Por ejemplo, mi estructura de directorios es:
my-project/
├── docs/
├── data/ <---- contains around 200k files.
└── analyser/
Como todavía me encanta completar, ¿hay alguna forma de desactivar esta función solo en el data/
directorio? ¿Como establecer un tiempo de espera de 5 segundos o un script que desactiva automáticamente la finalización cuando se encuentra dentro de un directorio específico?
Respuesta1
Esto no es perfecto, pero, de nuevo, completar bash es algo bastante complicado...
La forma más sencilla es por comando, es un poco más flexible que FIGNORE
, puedes hacer:
complete -f -X "/myproject/data/*" vi
Esto indica a Autocompletar que la finalización vi
es para archivos y que elimine los patrones que coincidan con el -X
filtro. La desventaja es que el patrón no está normalizado, por lo que ../data
las variaciones no coincidirán.
La mejor opción podría ser una PROMPT_COMMAND
función personalizada:
# associative arrays of non-autocomplete directories
declare -A noacdirs=([/myproject/data]=1 )
function _myprompt {
[[ -n "${noacdirs[$PWD]}" ]] && {
echo autocomplete off
bind 'set disable-completion on'
} || {
echo autocomplete on
bind 'set disable-completion off'
}
}
PROMPT_COMMAND=_myprompt
Estedesactiva la finalización(completamente) cuando estés en el directorio,perolo desactiva para cada ruta, no solo para los archivos de ese directorio.
En general, sería más útil deshabilitar esto selectivamente para rutas definidas, pero creo que la única forma es usar una función de finalización predeterminada (bash-4.1 y posterior con complete -D
) y mucho desorden.
Estedeberíafunciona para ti, peropuedetienen efectos secundarios no deseados (es decir, cambios en la finalización esperada en algunos casos):
declare -A noacdirs=([/myproject/data]=1 )
_xcomplete() {
local cur=${COMP_WORDS[COMP_CWORD]} # the current token
name=$(readlink -f "${cur:-./}") # poor man's path canonify
dirname=$(dirname "$name/.")
[[ -n "${noacdirs[$dirname]}" ]] && {
COMPREPLY=( "" ) # dummy to prevent completion
return
}
# let default kick in
COMPREPLY=()
}
complete -o bashdefault -o default -F _xcomplete vi
Esto funciona para completar vi
, se pueden agregar otros comandos según sea necesario. Debería detener la finalización de archivos en los directorios nombrados independientemente de la ruta o el directorio de trabajo.
Creo que el enfoque general complete -D
es agregar dinámicamente funciones de finalización para cada comando a medida que se encuentra. Es posible que también sea necesario agregar complete -E
(finalización del nombre del comando cuando el búfer de entrada esté vacío).
Actualizar
Aquí hay una versión híbrida de las PROMPT_COMMAND
soluciones de función de finalización y, creo que es un poco más fácil de entender y piratear:
declare -A noacdirs=([/myproject/data]=1 [/project2/bigdata]=1)
_xcomplete() {
local cmd=${COMP_WORDS[0]}
local cur=${COMP_WORDS[COMP_CWORD]} # the current token
[[ -z "$cur" && -n "$nocomplete" ]] && {
printf "\n(restricted completion for $cmd in $nocomplete)\n"
printf "$PS2 $COMP_LINE"
COMPREPLY=( "" ) # dummy to prevent completion
return
}
COMPREPLY=() # let default kick in
}
function _myprompt {
nocomplete=
# uncomment next line for hard-coded list of directories
[[ -n "${noacdirs[$PWD]}" ]] && nocomplete=$PWD
# uncomment next line for per-directory ".noautocomplete"
# [[ -f ./.noautocomplete ]] && nocomplete=$PWD
# uncomment next line for size-based guessing of large directories
# [[ $(stat -c %s .) -gt 512*1024 ]] && nocomplete=$PWD
}
PROMPT_COMMAND=_myprompt
complete -o bashdefault -o default -F _xcomplete vi cp scp diff
Esta función de solicitud establece la nocomplete
variable cuando ingresa a uno de los directorios configurados. El comportamiento de finalización modificado solo se activa cuando esa variable no está en blancoysolo cuando intenta completar desde una cadena vacía, permitiendo así completar nombres parciales (elimine la -z "$cur"
condición para evitar la finalización total). Comente las dos printf
líneas para un funcionamiento silencioso.
Otras opciones incluyen un archivo de bandera por directorio .noautocomplete
que puede colocar touch
en un directorio según sea necesario; y adivinar el tamaño del directorio usando GNU stat
. Puede utilizar cualquiera o todas esas tres opciones.
(El stat
métodoes solo una suposición, el tamaño del directorio informado crece con su contenido, es una "marca máxima" que generalmente no se reduce cuando los archivos se eliminan sin alguna intervención administrativa. Es más económico que determinar el contenido real de un directorio potencialmente grande. El comportamiento preciso y el incremento por archivo dependen del sistema de archivos subyacente. Lo encuentro un indicador confiable al menos en sistemas Linux ext2/3/4.)
bash agrega un espacio adicional incluso cuando se devuelve una finalización vacía (esto solo ocurre cuando se completa al final de una línea). Puede agregar -o nospace
al complete
comando para evitar esto.
Un inconveniente restante es que si retrocede el cursor hasta el inicio de un token y presiona la pestaña, la finalización predeterminada se activará nuevamente. Considérelo una característica ;-)
(O podrías perder el tiempo ${COMP_LINE:$COMP_POINT-1:1}
si te gusta la ingeniería excesiva, pero encuentro que bash no establece las variables de finalización de manera confiable cuando haces una copia de seguridad e intentas completar en medio de un comando).
Respuesta2
Si su data
directorio contiene archivos con un sufijo específico,p.ej .out
, luego puede configurar su bash
variable y estas serán ignoradas. Aunque también es posible utilizar nombres de directorios, esto no ayuda con los nombres de directorios de trabajo actuales.FIGNORE
".out"
Ejemplo:
Cree miles de archivos de prueba de 100 KB en un host físico con discos duros raid 1:
for i in {1..200000}; do dd if=/dev/urandom bs=102400 count=1 of=file$i.json; done
Establecer la bash
variable:
$ FIGNORE=".json"
Cree el archivo de prueba:
$ touch test.out
Prueba en5.000archivos:
$ ls *.json|wc -l
5587
$ vi test.out
No hay demora entre el vi y el single tab
antes de test.out
que aparezca.
Prueba en50.000archivos:
$ ls *.json|wc -l
51854
$ vi test.out
Una sola pestaña crea una fracción de segundo de retraso antes de test.out
que aparezca.
Prueba en200.000archivos:
$ ls *.json|wc -l
bash: /bin/ls: Argument list too long
$ ls | awk 'BEGIN {count=0} /.*.json/ {count++} END {print count}'
200000
$ vi test.out
Aparece un retraso de 1 segundo entre el vi y el single tab
anterior .test.out
Referencias:
Extracto de man bash
FIGNORE
A colon-separated list of suffixes to ignore when performing filename completion (see READLINE below). A filename whose suffix matches one of the entries in FIGNORE is
excluded from the list of matched filenames. A sample value is ".o:~".
Respuesta3
Supongo que esto es lo que quieres (tomé prestado un código de @ mr.spuratic)
Tenga en cuenta que esto no le impide presionar TAB usando la ruta completa (por ejemplo,vim /directory/contains/lots/files<tab><tab>
function cd() {
builtin cd "$@"
local NOCOMPLETION=( "/" "/lib" )
local IS_NOCOMPLETION=0
for dir in "${NOCOMPLETION[@]}"
do
echo $dir
if [[ $(pwd) == "$dir" ]]
then
echo "disable completion"
bind "set disable-completion on"
IS_NOCOMPLETION=1
return
fi
done
if [[ $IS_NOCOMPLETION -eq 0 ]]
then
echo "enable completion"
bind "set disable-completion off"
fi
}