bash hoàn thành cho các mẫu tên hoặc thư mục


12

Tôi đang cố gắng để có được một kịch bản hoàn thành bash được thiết lập và gặp một số rắc rối.

Tôi muốn thiết lập nó để các phần hoàn thành được liệt kê là các tệp khớp với một phần mở rộng hoặc thư mục cụ thể (có thể chứa hoặc không chứa các tệp của phần mở rộng đó).

Vấn đề tôi gặp phải là cách duy nhất tôi có thể có được các phần hoàn thành để chứa các tệp thư mục là bằng cách sử dụng một cái gì đó như -o plusdirs -f -X '!*.txt', nhưng khi tôi để bash hoàn thành một trong các thư mục, nó chỉ thêm một khoảng trắng vào cuối, chứ không phải là một gạch chéo.

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

  #COMPREPLY=( $( compgen -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -f -G '*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o filenames -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o dirnames  -f -X '!*.txt' -- $cur ) )
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
  return 0
}

complete -F _xyz xyz

Tôi cũng đã thử tất cả các dòng nhận xét, nhưng chúng thậm chí không mở rộng các thư mục.

Để thử nghiệm, tôi đã chạy cái này trong một thư mục có một tệp .txt và một thư mục "dir" (với tệp .txt bên trong nó, mặc dù điều đó chưa thành vấn đề). Nhập xyz <TAB>với chức năng này liệt kê thư mục và tệp .txt, nhưng gõ xyz d<TAB>mở rộng thành xyz dir(tốt, với một khoảng trắng sau "dir").

Câu trả lời:


10

Nếu bạn nhìn vào hàm _cd()trong / etc / bash_completion , bạn sẽ thấy rằng nó tự nối thêm dấu gạch chéo và nó hoàn thành được gọi với tùy chọn -o nospacecho cd .

Bạn có thể làm tương tự cho xyz , nhưng phải xác minh riêng nếu đối sánh tìm thấy là một thư mục (nếu vậy, hãy thêm dấu gạch chéo) hoặc một tệp (nếu vậy, hãy thêm khoảng trắng). Điều này nên được thực hiện trong một vòng lặp for để xử lý tất cả các kết quả tìm thấy.

Ngoài ra, để xử lý đúng các đường dẫn có chứa khoảng trắng, bạn phải đặt dấu phân cách tệp bên trong thành chỉ dòng mới và thoát khỏi khoảng trắng. Sử dụng IFS=$'\n'kết hợp với printf %qlàm cho hoàn thành công việc với hầu hết tất cả các nhân vật. 1 Chăm sóc đặc biệt phải được thực hiện để không thoát khỏi không gian dấu.

Sau đây nên làm việc:

_xyz ()
{
    local IFS=$'\n'
    local LASTCHAR=' '

    COMPREPLY=($(compgen -o plusdirs -f -X '!*.txt' \
        -- "${COMP_WORDS[COMP_CWORD]}"))

    if [ ${#COMPREPLY[@]} = 1 ]; then
        [ -d "$COMPREPLY" ] && LASTCHAR=/
        COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR")
    else
        for ((i=0; i < ${#COMPREPLY[@]}; i++)); do
            [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/
        done
    fi

    return 0
}

complete -o nospace -F _xyz xyz

1 Ký tự dòng mới là ngoại lệ rõ ràng ở đây, vì nó là một dấu tách tệp nội bộ.


Điều này hoạt động rất tốt (mặc dù nó quá tệ, nó không được tích hợp). Cảm ơn!
Cướp tôi

1
Bất kỳ lý do nào để không sử dụng "$ 2" thay vì "$ {COMP_WORDS [COMP_CWORD]}"?
Edward Falk

3

Tôi nghĩ rằng giải pháp đơn giản này hoạt động trong đó:

  1. Khớp các thư mục và tệp kết thúc bằng .txt
  2. Xử lý khoảng trắng trong tên tệp
  3. Thêm một dấu gạch chéo ở cuối hoàn thành thư mục không có dấu cách
  4. Thêm không gian vào cuối của một trận đấu hoàn thành tập tin

Chìa khóa đã qua -o filenamesđể hoàn thành. Điều này đã được thử nghiệm trên GNU bash 3.2.25 trên RHEL 5.3 và GNU bash 4.3.18 trên osx

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}

  local IFS=$'\n'
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
}

complete -o filenames -F _xyz xyz

Vâng, điều đó dường như làm việc tuyệt vời. Đơn giản hơn nhiều, cảm ơn vì đã nắm bắt được lập luận quan trọng!
Cướp tôi
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.