Làm thế nào để đối phó với sự kết thúc của các tùy chọn - trong getopts


9

Tôi sử dụng getopts để phân tích các đối số trong các tập lệnh bash như

while getopts ":hd:" opt; do
  case $opt in
    d ) echo "directory = $OPTARG"; mydir="$OPTARG"; shift $((OPTIND-1)); OPTIND=1 ;;
    h ) helptext
      graceful_exit ;;
    * ) usage
      clean_up
      exit 1
  esac
done

exeparams="$*"

exeparamssẽ giữ bất kỳ tùy chọn / đối số chưa được chỉnh sửa. Vì tôi muốn sử dụng exeparam để giữ các tùy chọn cho một lệnh được thực thi trong tập lệnh (có thể trùng với các tùy chọn riêng của tập lệnh), tôi muốn sử dụng - để kết thúc các tùy chọn được truyền cho tập lệnh. Nếu tôi vượt qua, vd

myscript -d myscriptparam -- -d internalparam

exeparams sẽ giữ

-- -d internalparam

Bây giờ tôi muốn loại bỏ phần dẫn --để truyền các đối số này cho lệnh nội bộ. Có một cách thanh lịch để làm điều này hay tôi có thể có được một chuỗi chỉ giữ phần còn lại mà không có --từ getopts?


Đặt shift; OPTIND=1bên trong getoptsvòng lặp có lẽ không phải là cách tốt nhất để làm điều đó. Nó chỉ hoạt động trong trường hợp của bạn vì bạn chỉ có 2 tùy chọn và trong tất cả các tùy chọn khác bạn chỉ cần thoát khỏi tập lệnh. Nếu không, bạn cần shift; OPTIND=1trong mọi tùy chọn, có nghĩa là mã trùng lặp (thực tiễn xấu). Chỉ cần thực hiện shift $((OPTIND - 1))ngay sau khi kết thúc vòng lặp - đây là cách thông thường nhất và có lẽ cũng hiệu quả nhất.
jw013

Câu trả lời:


7

Làm thế nào về:

# ... getopts processing ...

[[ $1 = "--" ]] && shift
exeparams=("$@")

Lưu ý, bạn nên sử dụng một mảng để giữ các tham số. Điều đó sẽ xử lý đúng bất kỳ đối số có chứa khoảng trắng. Dereference mảng với"${exeparams[@]}"


1
Điều này giả định rằng không có đối số giữa phần cuối của các tùy chọn và --, tức là script foo -- barsẽ chuyển foo -- barsang chương trình bên ngoài. Câu trả lời của tôi không đưa ra giả định đó vì nó không được nêu rõ trong câu hỏi.
jw013

Ngoại trừ nơi OP nói "Bây giờ tôi muốn xóa vị trí dẫn đầu -"
glenn jackman

Đó là ví dụ -- -d internalparams. Trong mọi trường hợp, câu trả lời của tôi đủ chung để xử lý một trong hai trường hợp.
jw013

14

Sử dụng tích hợp shift. Đầu tiên, làm bình thường getoptscho kịch bản của bạn. Khi vòng lặp đó hoàn thành,

shift "$((OPTIND - 1))"

sẽ chuyển ra tất cả các tùy chọn đã được xử lý.

Từ đó, bạn sẽ phải xử lý xong các đối số không phải tùy chọn, nếu có, cho phần đầu tiên của tập lệnh (trước phần --). Khi bạn gặp phải --, hãy dịch chuyển nó ra cho đến khi chỉ còn lại phần sau ( -d internalparamphần tiếp theo --). Một cách để làm điều này (sử dụng bashcú pháp):

while [[ $# -gt 0 ]]; do
    # process next argument
    case $1 in
    foo) # process foo
    ;;
    --) shift; break;; # found '--', discard it and exit loop
    *) # handle unrecognized argument
    ;;
    esac
    # not '--', so discard the argument and continue
    shift
done

Cuối cùng, chỉ còn lại các tùy chọn / đối số thứ hai mà bạn có thể truyền lại. Đừng KHÔNG sử dụng $*để vượt qua các thông số còn lại để lệnh khác. Sử dụng "$@"thay thế, mà bảo tồn tách từ gốc.

external_command "$@"

Vâng cảm ơn! Nhưng chính xác làm thế nào để tôi tìm thấy --?
highsciguy
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.