Desabilitar a conclusão da tabulação no Bash para algum diretório que contenha um grande número de arquivos?

18

Estou trabalhando com um grande número de arquivos, que eu mantenho em um diretório. Toda vez que eu entro naquele diretório e acidentalmente pressiono Tab duas vezes, demora muito (pode demorar mais de um minuto) para mostrar arquivos que combinam com o padrão, e estou bastante irritado com esse comportamento.

Por exemplo, minha estrutura de diretórios é:

my-project/
├── docs/
├── data/        <---- contains around 200k files.
└── analyser/

Como ainda amo a conclusão, existe alguma maneira de desativar esse recurso apenas no diretório data/ ? Como definir o tempo limite por 5 segundos, ou um script que desativa automaticamente a conclusão quando dentro do diretório específico?

    
por neizod 13.10.2014 / 16:15

3 respostas

9

Isso não é perfeito, mas a conclusão do bash é bem complicada ...

A maneira mais simples é por comando, é um pouco mais flexível que FIGNORE , você pode fazer:

 complete -f -X "/myproject/data/*" vi

Isso instrui o preenchimento automático de que a conclusão de vi é para arquivos e para remover padrões correspondentes ao filtro -X . A desvantagem é que o padrão não é normalizado, portanto, ../data e variações não corresponderão.

A próxima melhor coisa pode ser uma função PROMPT_COMMAND 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

Esta desativa a conclusão (completamente) quando você está no diretório, mas desativa-o para todos os caminhos, não apenas arquivos naquele diretório.

Seria mais útil desativar isso seletivamente para caminhos definidos, mas acredito que a única maneira é usar uma função de conclusão padrão (bash-4.1 e posterior com complete -D ) e muita confusão.

Isso deve funcionar para você, mas pode ter efeitos colaterais indesejados (ou seja, alterações na conclusão esperada em alguns 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

Isso funciona para a conclusão de vi , outros comandos podem ser adicionados conforme necessário. Deve parar a conclusão de arquivos nos diretórios nomeados, independentemente do caminho ou diretório de trabalho.

Eu acredito que a abordagem geral com complete -D é adicionar dinamicamente funções de conclusão para cada comando conforme ele é encontrado. Também é necessário adicionar complete -E (conclusão do nome do comando quando o buffer de entrada estiver vazio).

Atualizar Aqui está uma versão híbrida das soluções PROMPT_COMMAND e função de conclusão, é um pouco mais fácil de entender e hackear, eu acho:

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 função de prompt define a variável nocomplete quando você insere um dos diretórios configurados. O comportamento de conclusão modificado só entra em ação quando essa variável não estiver em branco e apenas quando você tentar concluir uma string vazia, permitindo a conclusão de nomes parciais (remova a condição -z "$cur" para evitar a conclusão completamente) . Comente as duas linhas printf para operação silenciosa.

Outras opções incluem um arquivo% flag .noautocomplete por diretório, que você pode usar touch em um diretório, conforme necessário; e adivinhando o tamanho do diretório usando o GNU stat . Você pode usar qualquer uma ou todas essas três opções.

(O método stat é apenas um palpite , o tamanho do diretório relatado aumenta com o seu conteúdo, é um "limite máximo" que normalmente não diminui quando os arquivos são excluídos sem algum procedimento administrativo É mais barato do que determinar o conteúdo real de um diretório potencialmente grande.Comportamento preciso e incremento por arquivo depende do sistema de arquivos subjacente.Eu acho um indicador confiável em sistemas linux ext2 / 3/4, pelo menos.

O

bash adiciona um espaço extra, mesmo quando uma conclusão vazia é retornada (isso ocorre apenas ao completar no final de uma linha). Você pode adicionar -o nospace ao comando complete para evitar isso.

Uma coisinha remanescente é que, se você fizer o backup do cursor para o início de um token e clicar na guia, a conclusão padrão será ativada novamente. Considere isso como um recurso; -)

(Ou você pode andar com ${COMP_LINE:$COMP_POINT-1:1} se você gosta de engenharia excessiva, mas acho que o próprio bash falha em definir as variáveis de conclusão de forma confiável quando você faz backup e tenta completar no meio de um comando.)

    
por 14.10.2014 / 15:55
6

Se o diretório data contiver arquivos com um sufixo específico, por exemplo, .out , você poderá definir seu bash variable FIGNORE to ".out" e eles serão ignorados. Embora seja possível usar nomes de diretórios também, isso não ajuda nos nomes atuais de diretórios de trabalho.

Exemplo:

Crie milhares de arquivos de teste de 100 KB no host físico com HDs de RAID 1:

for i in {1..200000}; do dd if=/dev/urandom bs=102400 count=1 of=file$i.json; done

Defina a variável bash :
$ FIGNORE=".json"

Crie o arquivo de teste:% $ touch test.out

Teste em 5.000 arquivos:

$ ls *.json|wc -l
5587
$ vi test.out

Nenhum atraso entre o vi e o único tab antes de test.out aparecer.

Teste em 50.000 arquivos:

$ ls *.json|wc -l
51854
$ vi test.out

A guia "Único" cria uma fração de segundo antes que test.out apareça.

Teste em arquivos 200.000 :

$ 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

Atraso de 1 segundo entre o vi e o único tab antes de test.out aparecer.

Referências:

Excert do homem 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:~".
    
por 13.10.2014 / 16:53
0

Acho que isso é o que você quer (emprestado algum código de @ mr.spuratic)

Observe que isso não impede que você pressione TAB usando o caminho completo (por exemplo, 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
}  
    
por 14.10.2014 / 22:39