2012-05-18 10 views
12

Hoàn thành bash sau đây chuyển một loạt các từ có thể (tức là các lần hoàn thành) để tổng hợp.Tự động hoàn thành Bash - Cách chuyển mảng này để biên dịch mà không có khoảng trống đáng kể bị thu gọn?

basenames=("foo" "fu bar" "baz"); 

COMPREPLY=($(compgen -W "${basenames[*]}" -- "${COMP_WORDS[COMP_CWORD]}")) 

Vấn đề là khoảng trắng trong phần tử mảng không được giữ nguyên, đó là "thanh foo" được coi là thành phần nhờ tách từ. Có cách nào để bảo vệ khoảng trống, sao cho 3 phần tử được hiển thị chứ không phải 4?

EDIT

basenames chứa tên tập tin, đó là hầu hết các nhân vật (ngoài/và \ 0) được cho phép.

EDIT 2

Cờ -W hy vọng một từ duy nhất, đó là một cái gì đó giống như foo bar foobar. Chuyển nhiều phần tử cho nó (đây là những gì ${basenames[@]} sẽ làm) sẽ không hoạt động.

EDIT 3

Thay đổi mảng basenames examplary (vì vậy foofoo từ foo bar sẽ không bị sụp đổ).

Sử dụng một dòng mới để tách các từ hoạt động:

local IFS=$'\n' 
COMPREPLY=($(compgen -W "$(printf "%s\n" "${basenames[@]}")" -- ${COMP_WORDS[COMP_CWORD]}")) 

Sử dụng \0 không:

local IFS=$'\0' 
COMPREPLY=($(compgen -W "$(printf "%s\0" "${basenames[@]}")" -- ${COMP_WORDS[COMP_CWORD]}")) 

Trả lời

8

Tại sao bận tâm với compgen? Chỉ cần thêm chúng vào COMPREPLY theo cách thủ công. Sau đây sẽ hoàn thành các tên tệp phù hợp từ /some/path, xử lý tên tệp một cách an toàn.

some_completion_function() { 
    local files=("/some/path/$2"*) 
    [[ -e ${files[0]} ]] && COMPREPLY=("${files[@]##*/}") 
} 

Không thể có compgen xử lý tên tệp một cách an toàn.

+0

+1 Đây là cách tôi thực sự đạt được những gì tôi muốn. Lời khuyên thực sự tốt! – helpermethod

+0

"$ 2" và "## * /" là gì? – oluc

+0

## */xóa đầu cho đến '/' cuối cùng; $ 2 là từ hoàn thành hiện tại; phải không? – oluc

-2

Bạn nên hầu như luôn luôn sử dụng một ít dấu hiệu thay vì một dấu hoa thị subscript một mảng .

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

từ man bash (hoặc xem Bash Reference Manual):

Nếu subscript là @ hoặc *, từ mở rộng cho tất cả các thành viên của tên. Các chỉ số này chỉ khác nhau khi từ xuất hiện trong dấu ngoặc kép. Nếu từ được trích dẫn kép, thì ${name[*]} sẽ mở rộng thành một từ có giá trị của mỗi thành viên mảng được phân cách bằng ký tự đầu tiên của biến đặc biệt IFS và ${name[@]} mở rộng từng phần tử của tên thành một từ riêng biệt.

Nói cách khác, ở biểu mẫu dấu "làm phẳng" mảng. Biểu mẫu dấu hoa thị giữ nguyên nó.

+4

Nếu tôi thay thế * bằng @, quá trình tự động hoàn thành sẽ ngừng hoạt động hoàn toàn. – helpermethod

+7

'compgen -W' yêu cầu tất cả các lần hoàn thành được cung cấp trong một" từ "duy nhất, mà' [@] 'không thực hiện. Xem [câu trả lời của tôi cho câu hỏi trước] (http://stackoverflow.com/questions/3348443/a-confusion-about-array-versus-array-in-the-context-of-a-bash-comple/3355375# 3355375) để có giải thích chi tiết. –

+11

-1: Lời khuyên này rất lạc hậu vì nó chỉ đơn giản là không chính xác. '-W' mong đợi một * đối số duy nhất * và sử dụng' @ 'sẽ cung cấp cho bạn một số không xác định của chúng. – antak

1

Có lẽ điều này có thể làm:

COMPREPLY=($(compgen -W "$(printf "%q " "${basenames[*]}")" -- "${COMP_WORDS[COMP_CWORD]}")) 
+0

Không phải với '*', nhưng với '@' nó có vẻ hoạt động. –

+0

Nó gần như hoạt động, nhưng nó xử lý "foo bar" là 2 phần tử, trong khi tôi muốn nó hiển thị nó như một phần tử. – helpermethod

+0

@OliverWeiler: Bạn đã thử glenn's với một '@'? –