2012-05-09 27 views
6

Có cách nào để xác định rằng một lệnh cụ thể có trường hợp không nhạy cảm, mà không bật trường hợp vô cảm trên toàn cầu (ít nhất là cho vỏ đó)?Thiết lập trường hợp không nhạy cảm cho hoàn thành bash trên cơ sở từng lệnh

Trong trường hợp đặc biệt của tôi, tôi có một ứng dụng nhỏ mà mang lại cho tôi dòng lệnh truy cập vào cơ sở dữ liệu các địa chỉ email, vì vậy tôi gõ:

db get email john smith 

và nó trả lại với địa chỉ email của John Smith. Vì vậy, tôi đã quản lý để cho phép hoàn thành phần lớn bên trong ứng dụng: thiết

COMPREPLY=($(compgen -W "$(db --complete $COMP_CWORD "$COMP_WORDS[@]"}")" -- ${COMP_WORDS[COMP_CWORD]})) 

hoạt động để cho phép tôi tab-đầy đủ getemail. Tuy nhiên, nếu sau đó tôi nhập j<tab>, từ chối, bởi vì trong cơ sở dữ liệu email, nó được viết hoa chính xác. Tôi muốn nhận được bash để hoàn thành điều này anyway. (Nếu tôi sử dụng số vốn J, nó hoạt động.)

Nếu không, tôi có thể có tùy chọn --complete thay đổi trường hợp trả lời bằng cách khớp đầu vào, tôi cho rằng, nhưng lý tưởng là dòng lệnh sẽ khớp với cơ sở dữ liệu nếu tất cả có thể.

Lưu ý rằng tôi có điều này làm việc bên trong ứng dụng khi sử dụng readline, nó chỉ giao tiếp với bash mà có vẻ là một vấn đề.

Trả lời

6

Thực tế dường như không có cách nào để có compgen khớp với phân biệt chữ hoa chữ thường với danh sách từ (-W). Tôi thấy các giải pháp sau đây:

Giải pháp đơn giản: Dịch cả danh sách từ và mã thông báo đầu vào thành chữ thường đầu tiên. Lưu ý: Đây là chỉ một tùy chọn nếu được chấp nhận là có tất cả các lần hoàn thành biến thành chữ thường tất cả.

complete_lower() { 

    local token=${COMP_WORDS[$COMP_CWORD]} 
    local words=$(db --complete $COMP_CWORD "${COMP_WORDS[@]}") 

    # Translate both the word list and the token to all-lowercase. 
    local wordsLower=$(printf %s "$words" | tr [:upper:] [:lower:]) 
    local tokenLower=$(printf %s "$token" | tr [:upper:] [:lower:]) 

    COMPREPLY=($(compgen -W "$wordsLower" -- "$tokenLower")) 
} 

tốt hơn, nhưng giải pháp phức tạp hơn: Cuộn riêng, case-insensitive hợp logic của bạn:

complete_custommatch() { 

    local token=${COMP_WORDS[$COMP_CWORD]} 
    local words=$(db --complete $COMP_CWORD "${COMP_WORDS[@]}") 

    # Turn case-insensitive matching temporarily on, if necessary. 
    local nocasematchWasOff=0 
    shopt nocasematch >/dev/null || nocasematchWasOff=1 
    ((nocasematchWasOff)) && shopt -s nocasematch 

    # Loop over words in list and search for case-insensitive prefix match. 
    local w matches=() 
    for w in $words; do 
     if [[ "$w" == "$token"* ]]; then matches+=("$w"); fi 
    done 

    # Restore state of 'nocasematch' option, if necessary. 
    ((nocasematchWasOff)) && shopt -u nocasematch 

    COMPREPLY=("${matches[@]}") 
} 
+0

Các giải pháp trên dường như không hoàn toàn đúng vì nó chỉ trả về trận đấu đầu tiên thay vì tất cả các trận đấu . loại bỏ "break" nên giải quyết điều đó. Một vấn đề khác là điều này không làm việc một cách duyên dáng trên các phiên bản bash cũ hơn mà không có tùy chọn nocasematch. Tôi không biết giải pháp nào tốt nhất cho điều đó, nhưng tôi đã sử dụng trong tập lệnh SHOPT địa phương = $ (shopt -p) địa phương IGNORE_CASE = 0 [["$ {SHOPT # * shopt -u nocasematch} "==" $ SHOPT "]] || IGNORE_CASE = 1 – Neuron

+0

Cảm ơn, @Neuron: Tôi đã cập nhật mã để trả về tất cả các kết quả phù hợp. Đối với tùy chọn 'nocasematch' không có sẵn (bạn có biết trong phiên bản nó đã được giới thiệu không?): Người ta có thể sử dụng phép thử của bạn và sau đó, trong trường hợp không có tùy chọn, áp dụng' tr [: upper:] [: lower :] 'kỹ thuật trong phần thân của vòng lặp' for'. Một cách ngắn gọn hơn để thực hiện kiểm tra tính khả dụng tùy chọn là: 'local haveNoCaseMatch = 0 \ n [[-z" $ (shopt -q nocasematch 2> & 1) "]] && haveNoCaseMatch = 1 ' – mklement0

+0

Bạn nên viết như COMPREPLY = ("$ {matches [@]}") nếu không nó sẽ chia nhỏ các tùy chọn nhiều từ (ví dụ, tên tập tin) – Orwellophile

Các vấn đề liên quan