2012-05-08 29 views
16

Tôi đang tạo tập lệnh hoàn thành bash cho công cụ chia sẻ tệp tải lên ngữ nghĩa với curl.Cách ngăn hoàn thành bash thay thế ký tự khi tab hoàn thành

Với curl, bạn có thể làm:

curl -F var = @ tập tin

để tải lên một tập tin.

Ứng dụng của tôi có ngữ nghĩa tương tự và tôi muốn có thể hiển thị các tệp có thể sau khi nhấn '@'. Thật không may, điều này được chứng minh khó khăn:

cur="${COMP_WORDS[COMP_CWORD]}" 
prev="${COMP_WORDS[COMP_CWORD-1]}" 
if [[ "$cur" == @* && "$prev" == '=' ]]; then 
    COMPREPLY=($(compgen -f ${cur:1})) 
    return 0 
fi 

Vì vậy, nếu một lệnh (cho đến nay) kết thúc với:

[email protected] 

tập tin trong thư mục hiện sẽ hiển thị.

[email protected]/usr/                              
/usr/bin  /usr/games 

Vấn đề là nếu tôi thực sự nhấn tab để hoàn thành, dấu '@' biến mất!

var=/usr/bin 

Vì vậy, có vẻ như bash sẽ thay thế toàn bộ từ hiện tại bằng COMPREPLY theo thẻ.

Cách duy nhất để tránh điều này đã được để làm điều này:

 COMPREPLY=($(compgen -f ${cur:1})) 
     for ((i=0; i<${#COMPREPLY[@]}; i++)); 
     do 
      COMPREPLY[$i]='@'${COMPREPLY[$i]} 
     done                              

Nhưng bây giờ hoàn tab trông lạ để nói rằng ít nhất:

@/usr/bin  @/usr/games 

Liệu có cách nào để hiển thị một tập tin bình thường hoàn thành tab (không có tiền tố '@') nhưng giữ lại '@' khi nhấn tab?

+1

tạo ảnh vui nhộn câu hỏi! Tôi đã học được rất nhiều câu trả lời này. – sanmiguel

Trả lời

5

Vì vậy, điều này hấp dẫn tôi, vì vậy tôi đã đọc qua nguồn hoàn thành bash (có sẵn tại/etc/bash_completion).

Tôi đã xem biến này: ${COMP_WORDBREAKS}, có vẻ như cho phép kiểm soát những ký tự nào được sử dụng để phân tách các từ.

Tôi cũng đã xem hàm này, _get_cword và bổ sung _get_pword, cả hai được đề xuất sử dụng thay cho số ${COMP_WORDS[COMP_CWORD]}${COMP_WORDS[COMP_CWORD-1]} tương ứng.

Vì vậy, đặt tất cả điều này với nhau, tôi đã làm một số xét nghiệm và đây là những gì tôi đã đưa ra: điều này dường như làm việc cho tôi, ít nhất, hy vọng nó sẽ cho bạn quá:

# maintain the old value, so that we only affect ourselves with this 
OLD_COMP_WORDBREAKS=${COMP_WORDBREAKS} 
COMP_WORDBREAKS="${COMP_WORDBREAKS}@" 

cur="$(_get_cword)" 
prev="$(_get_pword)" 

if [[ "$cur" == '[email protected]' ]]; then 
    COMPREPLY=($(compgen -f ${cur:2})) 

    # restore the old value 
    COMP_WORDBREAKS=${OLD_COMP_WORDBREAKS} 
    return 0 
fi 

if [[ "$prev" == '[email protected]' ]]; then 
    COMPREPLY=($(compgen -f ${cur})) 

    # restore the old value 
    COMP_WORDBREAKS=${OLD_COMP_WORDBREAKS} 
    return 0 

fi 

Bây giờ , Tôi sẽ thừa nhận rằng các trường hợp phân chia if là một chút bẩn, chắc chắn có một cách tốt hơn để làm điều đó nhưng tôi cần thêm caffeine.

Hơn nữa, đối bất cứ điều gì nó có giá trị đối với bạn tôi cũng phát hiện ra trên đường đi các -P <prefix> lập luận để compgen, trong đó sẽ khiến bạn không cần phải lặp qua mảng $COMPREPLY[*]} sau khi gọi compgen, như vậy

COMPREPLY=($(compgen -P @ -f ${cur:1})) 

Đó là một chút dư thừa khi đối mặt với một giải pháp đầy đủ.

+1

Nghiên cứu tuyệt vời. Tôi thực sự thích nơi bạn đang đi với điều này. Từ giao diện của kịch bản, điều này sẽ làm việc hoàn thành tab như tôi mong muốn. Nhưng tôi có một mối quan tâm lớn. Tôi thấy rằng bạn đặt lại COMP_WORDBREAKS khi người dùng đã nhập ký tự = @. Nhưng điều gì sẽ xảy ra nếu anh ta không bao giờ làm? Dường như bash sẽ mãi mãi có COMP_WORDBREAKS được sửa đổi. Tất cả câu trả lời này dường như cần là một số cách được đảm bảo để đặt lại COMP_WORDBREAKS về giá trị ban đầu khi người dùng hoàn tất việc nhập dòng. – UsAaR33

+0

Bạn nói đúng - điều đó sẽ rời COMP_WORDBREAKS ở trạng thái đó. Tôi sẽ tìm một giải pháp và cập nhật. – sanmiguel

+0

Vì đây là câu trả lời tốt nhất cho đến nay, tôi sẽ cung cấp cho bạn tiền thưởng. Sẽ chấp nhận điều này (hoặc bất kỳ câu trả lời nào trong tương lai) khi giải quyết vấn đề đặt lại COMP_WODBREAKS. – UsAaR33

0

Hãy thử điều này ....

function test 
{ 
    COMPREPLY=() 
    local cur="${COMP_WORDS[COMP_CWORD]}" 
    local opts="Whatever sort of tabbing options you want to have!" 
    COMPREPLY=($(compgen -W "${opts}" -- ${cur})) 
} 
complete -F "test" -o "default" "test" 
# complete -F "test" -o "nospace" "sd" ## Use this if you do not want a space after the completed word 
+0

Bạn có thể mở rộng điều này không? Bạn đang hiển thị các khái niệm cơ bản về tập lệnh hoàn thành bash, nhưng vấn đề cơ bản của tôi sẽ được giải quyết như thế nào? – UsAaR33

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