Dosya adı desenleri veya dizinleri için bash tamamlama


13

Bir bash tamamlama komut dosyası ayarlamaya çalışıyorum ve bazı sorunlar yaşıyorum.

Listelenen tamamlamalar belirli bir uzantıyla eşleşen dosyaları veya dizinleri (bu uzantıya sahip dosyaları içerebilir veya içermeyebilir) olacak şekilde ayarlamak istiyorum.

Sahip olduğum sorun, dosyaları ve dizinleri içermek için tamamlamaları elde etmenin tek yolunun şuna benzer bir şey kullanmaktır -o plusdirs -f -X '!*.txt', ancak bash dizinlerden birini tamamlamasına izin verdiğimde, sadece sonuna kadar bir boşluk ekler. yırtmaç.

_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

Tüm yorum satırlarını da denedim, ancak dizinleri bile genişletmiyorlar.

Test için, bunu bir .txt dosyası ve bir dizin "dir" (içinde bir .txt dosyası ile, ancak bu önemli değil) ile bir dizinde çalıştırıyorum. xyz <TAB>Bu işlevle yazmak dizini ve .txt dosyasını listeler, ancak yazmak xyz d<TAB>genişler xyz dir("dir" ifadesinden sonra bir boşluk bırakarak).

Yanıtlar:


10

Eğer işlevi bakarsak _cd()içinde / etc / bash_completion , bunu sondaki kendisini çizgi ekler ve bu olduğunu göreceksiniz tam seçeneğiyle alır denilen -o nospaceiçin cd .

Aynı şeyi xyz için de yapabilirsiniz , ancak bulunan eşleşmenin bir dizin (eğik çizgi ekle) veya bir dosya (varsa boşluk ekle) olup olmadığını ayrı ayrı doğrulamanız gerekir. Bu, bulunan tüm eşleşmeleri işlemek için bir for döngüsünde yapılmalıdır.

Ayrıca, boşluk içeren yolları düzgün işlemek için, iç dosya ayırıcısını yalnızca yeni satıra ayarlamanız ve boşluklardan kaçmanız gerekir. İle IFS=$'\n'birlikte kullanmak printf %q, tamamlama neredeyse tüm karakterlerle çalışır. 1 Sondaki boşluktan kaçmamak için özel dikkat gösterilmelidir.

Aşağıdakiler işe yaramalıdır:

_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 Yeni satır karakteri buradaki bariz istisnadır, çünkü dahili bir dosya ayırıcısıdır.


Bu harika çalışıyor (çok kötü olsa da yerleşik değil). Teşekkürler!
Rob I

1
"$ {COMP_WORDS [COMP_CWORD]}" yerine "$ 2" kullanmamak için herhangi bir neden var mı?
Edward Falk

3

Bence bu basit çözüm şu şekilde çalışır:

  1. İle biten dizinleri ve dosyaları eşleştirir .txt
  2. Dosya adlarındaki boşlukları işler
  3. Sondaki boşluğu olmayan klasör tamamlamalarının sonuna eğik çizgi ekler
  4. Dosya tamamlama eşleşmesinin sonuna boşluk ekler

Anahtar -o filenamestamamlanmak için geçiyordu . Bu RHEL 5.3 üzerinde GNU bash 3.2.25 ve osx üzerinde GNU bash 4.3.18 üzerinde test edilmiştir

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

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

complete -o filenames -F _xyz xyz

Evet, bu harika çalışıyor gibi görünüyor. Çok daha basit, önemli argümanı yakaladığınız için teşekkürler!
Rob I
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.