Hoàn thành Bash cho các giá trị được phân tách bằng dấu phẩy


16

Tôi muốn tạo quy tắc hoàn thành cho danh sách tham số được phân tách bằng dấu phẩy. Ví dụ: tôi có lệnh nhận danh sách tên máy chủ:

myscript -s name1,name2,name3

Tại thời điểm này, tôi đã quản lý để viết hoàn thành sau đây:

_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
}

Nhưng nó có ít nhất 2 vấn đề:

  1. Đề xuất cho giá trị hiện tại bao gồm tất cả các giá trị trước đó trong tiền tố của chúng.
  2. Nó không xem xét các giá trị trùng lặp.

Các thực hành tốt nhất cho các trường hợp như vậy là gì? Có lẽ bash-hoàn thành có một số chức năng đi kèm cho danh sách csv?


3
Điều có thể giúp là bạn có thể chia các giá trị được phân tách bằng dấu phẩy thành một danh sách lặp như thế này: IFS=, LIST=("$VARIABLE")trong đó $ VARIABLE chứa các giá trị được phân tách bằng dấu phẩy của bạn.
Michael Ehrenreich

2
Ý tưởng hay @MichaelEhrenreich, nhưng bạn không được trích dẫn $VARIABLE, nếu không việc phá vỡ từ sẽ không xảy ra. Chỉ cần sử dụng IFS=, LIST=($VARIABLE).
Guss

Câu trả lời:


6

Về cơ bản không có cách nào để khắc phục các sự cố mà bạn mô tả, vì bash sử dụng các giá trị COMPREPLYtrực tiếp trong màn hình và sau đó để thay thế văn bản của người dùng - trong khi để có được những gì bạn muốn, trước tiên bạn cần tạo ra các hoàn thành có thể (chỉ là bổ sung Tên máy chủ, không có tiền tố) để bash hiển thị, sau đó khi bash sắp thay thế văn bản người dùng bằng chuỗi không xung đột dài nhất, bạn cần gọi lại tập lệnh của mình để tạo văn bản có tiền tố - và bash không có cơ sở cho điều đó.

Điều tốt nhất mà tôi có thể đưa ra là COMPREPLYtạo ra chỉ với từ đầu tiên có toàn bộ tiền tố ( COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) )), để nếu chỉ có một lần hoàn thành có thể, nó sẽ tự động hoàn thành chính xác, trong khi nếu có nhiều hơn một lần hoàn thành có thể , sau đó bash sẽ không xóa những gì đã gõ cho đến nay (vì từ đầu tiên trong đó COMPREPLYcó toàn bộ tiền tố và do đó khớp với văn bản hiện đang nhập và sẽ được chọn bởi bash để thay thế văn bản của người dùng) và sẽ hiển thị các tùy chọn không có tiền tố - ngoại trừ cho một từ đã chứa tiền tố, vì vậy đầu ra sẽ như thế này:

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

"Táo" như được sắp xếp cuối cùng trong các tùy chọn hoàn thành vì nó mang tiền tố bắt đầu bằng "b" - rất khó hiểu. Vì vậy, tôi không khuyên bạn nên làm điều đó.

Về các bản sao - để không hiển thị các bản sao, bạn chỉ cần đột $prefixnhập vào phần của nó (dễ dàng IFS="," prefix_parts=($prefix):) và sau đó lặp lại chúng và chỉ để lại trong $serverscác tên chưa được liệt kê. Thật tẻ nhạt khi gõ, vì vậy tôi sẽ không hiển thị ở đây, nhưng tương đối tầm thường nên tôi chắc chắn bạn có thể quản lý :-).

Để tóm tắt, tôi không nghĩ bạn nên sử dụng các giá trị được phân tách bằng dấu phẩy cho các tùy chọn đầu vào, ít nhất là nếu bạn mong đợi bash sẽ giúp bạn hoàn thành.

Bạn có thể hỗ trợ một định dạng tùy chọn như thế này: command -s <server> [<server> [..]]và sau đó để hoàn thành các mục khác ngoài mục ngay sau -stùy chọn, chỉ cần quét lại qua $COMP_WORDSmảng $COMP_CWORDcho đến khi bạn tìm thấy một tùy chọn (chuỗi khớp -*) và nếu "-s" của nó bạn cần phải hoàn thành tên máy chủ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.