¿Deshabilitar la finalización de tabulaciones en Bash para algún directorio que contenga una gran cantidad de archivos?

¿Deshabilitar la finalización de tabulaciones en Bash para algún directorio que contenga una gran cantidad de archivos?

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 vies para archivos y que elimine los patrones que coincidan con el -Xfiltro. La desventaja es que el patrón no está normalizado, por lo que ../datalas variaciones no coincidirán.

La mejor opción podría ser una PROMPT_COMMANDfunció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 -Des 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_COMMANDsoluciones 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 nocompletevariable 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 printflíneas para un funcionamiento silencioso.

Otras opciones incluyen un archivo de bandera por directorio .noautocompleteque puede colocar touchen 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 statmé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 nospaceal completecomando 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 datadirectorio contiene archivos con un sufijo específico,p.ej .out, luego puede configurar su bashvariable 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 bashvariable:
$ 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 tabantes de test.outque 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.outque 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 tabanterior .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
}  

información relacionada