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 FIGNORE
você 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 -X
filtro. A desvantagem é que o padrão não é normalizado e, portanto, ../data
as variações não correspondem.
A próxima melhor opção pode ser uma PROMPT_COMMAND
funçã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_COMMAND
soluçõ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 nocomplete
variá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 printf
linhas para operação silenciosa.
Outras opções incluem um arquivo de sinalização por diretório .noautocomplete
que você pode colocar touch
em 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 stat
mé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 nospace
ao complete
comando 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 data
diretório contém arquivos com um sufixo específico,por exemplo .out
, então você pode definir sua bash
variável FIGNORE
como ".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 bash
variá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 tab
antes test.out
aparece.
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.out
aparecer.
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 tab
antes test.out
aparece.
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
}