Desativar o preenchimento de guias no Bash para algum diretório que contém um grande número de arquivos?

Desativar o preenchimento de guias no Bash para algum diretório que contém um grande número de arquivos?

Estou trabalhando com um grande número de arquivos, que mantenho em um diretório. Cada vez que entro nesse diretório e pressiono acidentalmente Tabduas vezes, demora muito (pode levar mais de um minuto) para mostrar os arquivos que correspondem ao 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 adoro a conclusão, existe alguma maneira de desativar esse recurso apenas no data/diretório? Como definir o tempo limite para 5 segundos ou um script que desativa automaticamente a conclusão quando dentro de um diretório específico?

Responder1

Isso não é perfeito, mas a conclusão do bash é uma coisa bastante complicada ...

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

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

Isso instrui o preenchimento automático de que a conclusão vié para arquivos e para remover padrões que correspondam ao -Xfiltro. A desvantagem é que o padrão não é normalizado e, portanto, ../dataas variações não correspondem.

A próxima melhor opção pode ser uma PROMPT_COMMANDfunção 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

Essedesativa a conclusão(completamente) quando você está no diretório,masele o desativa para todos os caminhos, não apenas para os arquivos nesse diretório.

Seria mais útil desabilitar 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 bagunça.

Essedevetrabalhar para você, maspoderiatêm efeitos colaterais não intencionais (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. Ele deve interromper a conclusão dos arquivos nos diretórios nomeados, independentemente do caminho ou do diretório de trabalho.

Acredito que a abordagem geral complete -Dé adicionar dinamicamente funções de conclusão para cada comando conforme ele é encontrado. Também pode ser 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 PROMPT_COMMANDsoluções de 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 nocompletevariável 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 está em brancoesomente quando você tenta completar a partir de uma string vazia, permitindo assim a conclusão de nomes parciais (remova a -z "$cur"condição para evitar a conclusão completa). Comente as duas printflinhas para operação silenciosa.

Outras opções incluem um arquivo de sinalização por diretório .noautocompleteque você pode colocar touchem um diretório conforme necessário; e adivinhar o tamanho do diretório usando GNU stat. Você pode usar qualquer uma ou todas essas três opções.

(O statmétodoé apenas um palpite, o tamanho do diretório relatado aumenta com seu conteúdo, é um "limite máximo" que geralmente não diminui quando os arquivos são excluídos sem alguma intervenção administrativa. É mais barato do que determinar o conteúdo real de um diretório potencialmente grande. O comportamento preciso e o incremento por arquivo dependem do sistema de arquivos subjacente. Acho que é um indicador confiável, pelo menos em sistemas Linux ext2/3/4.)

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 algo -o nospaceao completecomando para evitar isso.

Um problema restante é que se você voltar o cursor para o início de um token e clicar em tab, a conclusão padrão será ativada novamente. Considere isso um recurso ;-)

(Ou você pode brincar ${COMP_LINE:$COMP_POINT-1:1}se gostar de engenharia excessiva, mas acho que o próprio bash não consegue definir as variáveis ​​de conclusão de maneira confiável quando você faz backup e tenta concluir no meio de um comando.)

Responder2

Se o seu datadiretório contém arquivos com um sufixo específico,por exemplo .out, então você pode definir sua bashvariável FIGNOREcomo ".out"e elas serão ignoradas. Embora também seja possível usar nomes de diretórios, isso não ajuda nos nomes de diretórios de trabalho atuais.

Exemplo:

Crie milhares de arquivos de teste de 100 KB em host físico com HDDs RAID 1:

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

Defina a bashvariável:
$ FIGNORE=".json"

Crie o arquivo de teste:
$ touch test.out

Teste em5.000arquivos:

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

Nenhum atraso entre o vi e o single tabantes test.outaparece.

Teste em50.000arquivos:

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

A guia única cria um atraso de fração de segundo antes de test.outaparecer.

Teste em200.000arquivos:

$ 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 single tabantes test.outaparece.

Referências:

Trecho 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:~".

Responder3

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

Observe que isso não impede que você pressione TAB usando o caminho completo (por exemplovim /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
}  

informação relacionada