Penyelesaian bash untuk nilai yang dipisahkan koma

16

Saya ingin membuat aturan penyelesaian untuk daftar parameter yang dipisahkan koma. Misalnya saya punya perintah yang menerima daftar nama server:

myscript -s name1,name2,name3

Saat ini saya sudah berhasil menulis penyelesaian sebagai berikut:

_myscript () {
  local cur prev opts

  _get_comp_words_by_ref cur prev

  opts='-s'

  servers='name1 name2 name3'

  if [[ ${cur} == -* ]] ; then
    COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
  else
    case "${prev}" in
      -s)
        if [[ "$cur" == *,* ]]; then
          local realcur prefix
          realcur=${cur##*,}
          prefix=${cur%,*}
          COMPREPLY=( $(compgen -W "${servers}" -P "${prefix}," -- ${realcur}) )
        else
          COMPREPLY=( $(compgen -W "${servers}" -- ${cur}) )
        fi
        ;;
      *)
        # do nothing
        ;;
    esac
  fi
}

Tetapi memiliki setidaknya 2 masalah:

  1. Saran untuk nilai saat ini mencakup semua nilai sebelumnya dalam awalannya.
  2. Itu tidak mempertimbangkan nilai duplikat.

Apa praktik terbaik untuk kasus seperti itu? Mungkin bash-completions memiliki beberapa fungsi yang dibundel untuk csv-list?

diffycat
sumber
3
Apa yang mungkin membantu adalah bahwa Anda dapat membagi nilai yang dipisah koma ke dalam daftar iterable seperti ini: di IFS=, LIST=("$VARIABLE")mana $ VARIABLE berisi nilai yang dipisahkan koma Anda.
Michael Ehrenreich
2
Ide bagus @MichaelEhrenreich, tetapi Anda tidak boleh mengutip $VARIABLE, jika tidak kata tidak akan terjadi. gunakan saja IFS=, LIST=($VARIABLE).
Guss

Jawaban:

6

Pada dasarnya tidak ada cara untuk memperbaiki masalah yang Anda gambarkan, karena bash menggunakan nilai-nilai di COMPREPLY secara langsung di layar dan kemudian mengganti teks pengguna - sementara untuk mendapatkan apa yang Anda inginkan, Anda harus terlebih dahulu menghasilkan penyelesaian yang mungkin (hanya tambahan nama server, tanpa awalan) untuk ditampilkan bash, maka ketika bash hendak mengganti teks pengguna dengan string non-konflik terpanjang, Anda perlu memanggil skrip Anda lagi untuk menghasilkan teks dengan awalan - dan bash tidak memiliki fasilitas untuk itu.

Yang terbaik yang bisa saya buat adalah memiliki COMPREPLYdihasilkan dengan hanya kata pertama yang memiliki seluruh awalan ( COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) )), sehingga jika hanya ada satu kemungkinan penyelesaian, itu selesai secara otomatis dengan benar, sedangkan jika ada lebih dari satu kemungkinan penyelesaian , maka bash tidak akan menghapus apa yang diketik sejauh ini (karena kata pertama dalam COMPREPLYmemiliki seluruh awalan dan dengan demikian cocok dengan teks yang diketik saat ini dan akan dipilih oleh bash untuk mengganti teks pengguna) dan akan menampilkan opsi tanpa awalan - kecuali untuk itu satu kata yang sudah berisi awalan, sehingga hasilnya akan terlihat seperti ini:

$ command -s banana,a
ananas     apricot    banana,apple

"apple" sebagai yang terakhir disortir dalam opsi penyelesaian karena membawa awalan yang dimulai dengan "b" - sangat membingungkan. Jadi saya tidak merekomendasikan melakukan itu.

Mengenai duplikat - agar tidak menunjukkan duplikat, Anda hanya perlu membobol $prefixbagiannya (mudah IFS="," prefix_parts=($prefix):) dan kemudian beralih pada mereka dan hanya meninggalkan $serversnama-nama yang belum terdaftar. Itu membosankan untuk mengetik, jadi saya tidak akan menunjukkannya di sini, tetapi relatif sepele jadi saya yakin Anda dapat mengelola :-).

Untuk meringkas, saya tidak berpikir Anda harus menggunakan nilai yang dipisahkan koma untuk opsi input, setidaknya jika Anda mengharapkan bash untuk membantu Anda dengan penyelesaian.

Anda dapat mendukung format opsi yang seperti ini: command -s <server> [<server> [..]]dan kemudian untuk penyelesaian entri selain yang segera setelah -sopsi, cukup memindai kembali melalui $COMP_WORDSarray dari $COMP_CWORDsampai Anda menemukan opsi (string yang cocok -*) dan jika "-s" maka Anda perlu melakukan penyelesaian nama server.

Guss
sumber