conclusão do bash para padrões ou diretórios de nome de arquivo

12

Estou tentando configurar um script de conclusão do bash e ter alguns problemas.

Eu gostaria de configurá-lo para que as conclusões listadas sejam arquivos correspondentes a uma extensão específica ou diretórios (que podem ou não conter arquivos dessa extensão).

O problema que estou tendo é que a única maneira de obter as inclusões para conter os diretórios e é usando algo como -o plusdirs -f -X '!*.txt' , mas quando eu deixo o bash completar um dos diretórios , apenas adiciona um espaço no final, em vez de uma barra.

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

  #COMPREPLY=( $( compgen -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -f -G '*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o filenames -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o dirnames  -f -X '!*.txt' -- $cur ) )
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
  return 0
}

complete -F _xyz xyz

Eu também tentei todas as linhas comentadas, mas elas nem expandem os diretórios.

Para testar, eu tenho executado isso em um diretório com um arquivo .txt e um diretório "dir" (com um arquivo .txt dentro dele, embora isso não importe ainda). Digitar xyz <TAB> com essa função lista o diretório e o arquivo .txt, mas digitar xyz d<TAB> expande para xyz dir (bem, com um espaço após "dir").

    
por Rob I 12.03.2013 / 15:48

2 respostas

10

Se você olhar para a função _cd() em / etc / bash_completion , verá que ela anexa a barra à direita e que completa é chamada com o caractere opção -o nospace para cd .

Você pode fazer o mesmo para xyz , mas ter que verificar separadamente se a correspondência encontrada é um diretório (se for o caso, acrescentar barra) ou um arquivo (se for o caso, acrescentar espaço). Isso deve ser feito em um loop para processar todas as correspondências encontradas.

Além disso, para manipular corretamente os caminhos que contêm espaços, você precisa definir o separador de arquivo interno como somente nova linha e escapar dos espaços. Usar IFS=$'\n' em combinação com printf %q faz o trabalho de conclusão com quase todos os caracteres. 1 Cuidado especial deve ser tomado para não escapar do espaço à direita.

Os seguintes itens devem funcionar:

_xyz ()
{
    local IFS=$'\n'
    local LASTCHAR=' '

    COMPREPLY=($(compgen -o plusdirs -f -X '!*.txt' \
        -- "${COMP_WORDS[COMP_CWORD]}"))

    if [ ${#COMPREPLY[@]} = 1 ]; then
        [ -d "$COMPREPLY" ] && LASTCHAR=/
        COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR")
    else
        for ((i=0; i < ${#COMPREPLY[@]}; i++)); do
            [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/
        done
    fi

    return 0
}

complete -o nospace -F _xyz xyz

1 O caractere de nova linha é a exceção óbvia aqui, já que é um separador interno de arquivos.

    
por 12.03.2013 / 18:04
3

Acho que essa solução simples funciona nisso:

  1. Corresponde diretórios e arquivos que terminam em .txt
  2. Gerencia espaços nos nomes dos arquivos
  3. Adiciona uma barra no final das conclusões da pasta sem espaço à direita
  4. Adiciona espaço no final de uma correspondência de conclusão de arquivo

A chave estava passando -o filenames para concluir. Isso foi testado no GNU bash 3.2.25 no RHEL 5.3 e no GNU bash 4.3.18 no osx

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}

  local IFS=$'\n'
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
}

complete -o filenames -F _xyz xyz
    
por 26.08.2014 / 18:09