selesai bash untuk pola atau direktori nama file

12

Saya mencoba menyiapkan skrip penyelesaian bash dan mengalami masalah.

Saya ingin mengaturnya sehingga penyelesaian yang tercantum adalah file yang cocok dengan ekstensi tertentu, atau direktori (yang mungkin atau mungkin tidak mengandung file dari ekstensi itu).

Masalah yang saya alami adalah bahwa satu-satunya cara saya bisa mendapatkan penyelesaian untuk berisi file dan direktori adalah dengan menggunakan sesuatu seperti -o plusdirs -f -X '!*.txt', tetapi ketika saya membiarkan bash menyelesaikan salah satu direktori, itu hanya menambah ruang pada akhirnya, daripada sebuah memotong.

_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

Saya sudah mencoba semua baris komentar juga, tetapi mereka bahkan tidak memperluas direktori.

Untuk pengujian, saya sudah menjalankan ini dalam direktori dengan satu file .txt dan satu direktori "dir" (dengan file .txt di dalamnya, meskipun itu belum masalah). Mengetik xyz <TAB>dengan fungsi ini mencantumkan direktori dan file .txt, tetapi mengetik xyz d<TAB>diperluas ke xyz dir(well, dengan spasi setelah "dir").

Rob I
sumber

Jawaban:

10

Jika Anda melihat fungsi _cd()di / etc / bash_completion , Anda akan melihat bahwa itu menambahkan trailing slash itu sendiri dan yang lengkap dipanggil dengan opsi -o nospaceuntuk cd .

Anda dapat melakukan hal yang sama untuk xyz , tetapi harus memverifikasi secara terpisah jika kecocokan yang ditemukan adalah direktori (jika demikian, tambahkan slash) atau file (jika demikian, tambahkan ruang). Ini harus dilakukan dalam for loop untuk memproses semua kecocokan yang ditemukan.

Juga, untuk menangani jalur yang berisi spasi dengan benar, Anda harus mengatur pemisah file internal hanya baris baru dan keluar dari spasi. Menggunakan IFS=$'\n'dalam kombinasi dengan printf %qmembuat penyelesaian bekerja dengan hampir semua karakter. 1 Perhatian khusus harus diambil untuk tidak luput dari ruang trailing.

Berikut ini harus bekerja:

_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 Karakter baris baru adalah pengecualian yang jelas di sini, karena merupakan pemisah file internal.

Dennis
sumber
Ini berfungsi dengan baik (meskipun terlalu buruk itu tidak ada di dalamnya). Terima kasih!
Rob I
1
Adakah alasan untuk tidak menggunakan "$ 2" dan bukannya "$ {COMP_WORDS [COMP_CWORD]}"?
Edward Falk
3

Saya pikir solusi sederhana ini berfungsi di dalamnya:

  1. Cocok dengan direktori dan file yang berakhiran .txt
  2. Menangani spasi dalam nama file
  3. Menambahkan garis miring pada akhir penyelesaian folder tanpa spasi tambahan
  4. Menambahkan ruang di akhir kecocokan penyelesaian file

Kunci itu lewat -o filenamesuntuk menyelesaikan. Ini diuji pada GNU bash 3.2.25 pada RHEL 5.3 dan GNU bash 4.3.18 pada 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
Chad Skeeters
sumber
Ya itu sepertinya bekerja dengan baik. Jauh lebih sederhana, terima kasih untuk menangkap argumen penting!
Rob I