bash completamento per modelli di file o directory


12

Sto cercando di impostare uno script di completamento bash e ho qualche problema.

Vorrei impostarlo in modo che i completamenti elencati siano file corrispondenti a una determinata estensione o directory (che possono contenere o meno file di tale estensione).

Il problema che sto avendo è che l'unico modo per ottenere i completamenti per contenere file e directory è usando qualcosa di simile -o plusdirs -f -X '!*.txt', ma quando lascio che bash completi una delle directory, aggiunge semplicemente uno spazio alla fine, piuttosto che un 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

Ho provato anche tutte le righe commentate, ma non hanno nemmeno ampliato le directory.

Per i test, ho eseguito questo in una directory con un file .txt e una directory "dir" (con un file .txt al suo interno, anche se non ha ancora importanza). La digitazione xyz <TAB>con questa funzione elenca la directory e il file .txt, ma la digitazione si xyz d<TAB>espande in xyz dir(bene, con uno spazio dopo "dir").

Risposte:


10

Se guardate la funzione _cd()in / etc / bash_completion , vedrai che aggiunge il finale in sé slash che completa viene chiamato con l'opzione -o nospaceper il cd .

Puoi fare lo stesso per xyz , ma devi verificare separatamente se la corrispondenza trovata è una directory (in tal caso, aggiungi barra) o un file (in tal caso, aggiungi spazio). Questo dovrebbe essere fatto in un ciclo for per elaborare tutte le corrispondenze trovate.

Inoltre, per gestire correttamente i percorsi che contengono spazi, è necessario impostare il separatore di file interno su solo newline ed evitare gli spazi. L'uso IFS=$'\n'in combinazione con printf %qfa funzionare il completamento con quasi tutti i personaggi. 1 Prestare particolare attenzione a non sfuggire allo spazio finale.

Il seguente dovrebbe funzionare:

_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 Il carattere newline è l'ovvia eccezione qui, poiché è un separatore di file interno.


Funziona benissimo (anche se è un peccato che non sia integrato). Grazie!
Rob I

1
Qualche motivo per non usare "$ 2" invece di "$ {COMP_WORDS [COMP_CWORD]}"?
Edward Falk,

3

Penso che questa semplice soluzione funzioni nel senso che:

  1. Corrisponde a directory e file che finiscono in .txt
  2. Gestisce gli spazi nei nomi dei file
  3. Aggiunge una barra alla fine dei completamenti delle cartelle senza spazio finale
  4. Aggiunge spazio alla fine di una corrispondenza di completamento del file

La chiave stava -o filenamesper essere completata. Questo è stato testato su GNU bash 3.2.25 su RHEL 5.3 e GNU bash 4.3.18 su 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

Sì, sembra funzionare alla grande. Molto più semplice, grazie per aver colto l'argomento importante!
Rob I,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.