Bagaimana menangani akhir opsi - di getopts

9

Saya menggunakan getopts untuk mem-parsing argumen dalam skrip bash sebagai

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="$*"

exeparamsakan menyimpan opsi / argumen yang tidak diparsing. Karena saya ingin menggunakan exeparams untuk menyimpan opsi agar suatu perintah dapat dieksekusi di dalam skrip (yang dapat tumpang tindih dengan opsi skrip sendiri), saya ingin menggunakan - untuk mengakhiri opsi yang diteruskan ke skrip. Jika saya lulus mis

myscript -d myscriptparam -- -d internalparam

exeparams akan memegang

-- -d internalparam

Saya sekarang ingin menghapus yang memimpin --untuk meneruskan argumen ini ke perintah internal. Apakah ada cara yang elegan untuk melakukan ini atau bisakah saya mendapatkan string yang hanya memegang sisanya tanpa --dari getop?

kelas tinggi
sumber
Meletakkan shift; OPTIND=1di dalam getoptslingkaran mungkin bukan cara terbaik untuk melakukannya. Ini hanya berfungsi dalam kasus Anda karena Anda hanya memiliki 2 opsi dan di semua yang lain Anda hanya keluar dari skrip. Kalau tidak, Anda akan membutuhkan shift; OPTIND=1di setiap opsi, yang berarti kode duplikat (praktik buruk). Lakukan shift $((OPTIND - 1))segera setelah akhir loop - ini adalah cara yang paling konvensional dan mungkin yang paling efisien juga.
jw013

Jawaban:

7

Bagaimana tentang:

# ... getopts processing ...

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

Catatan, Anda harus menggunakan array untuk menyimpan parameter. Itu akan menangani dengan baik argumen yang berisi spasi putih. Dereferensi array dengan"${exeparams[@]}"

glenn jackman
sumber
1
Ini mengasumsikan bahwa tidak ada argumen antara akhir opsi dan --, yaitu script foo -- barakan diteruskan foo -- barke program eksternal. Jawaban saya tidak membuat asumsi itu karena tidak secara eksplisit dinyatakan dalam pertanyaan.
jw013
Kecuali di mana OP mengatakan "Saya sekarang ingin menghapus yang terkemuka -"
glenn jackman
Itu misalnya -- -d internalparams. Bagaimanapun, jawaban saya cukup umum untuk menangani kedua kasus tersebut.
jw013
14

Gunakan built-in shift. Pertama, lakukan hal yang normal getoptsuntuk skrip Anda. Setelah loop itu selesai,

shift "$((OPTIND - 1))"

akan menggeser semua opsi yang sudah diproses.

Dari sana, Anda harus menyelesaikan pemrosesan argumen non-opsi, jika ada, ke bagian pertama skrip (sebelum --). Setelah Anda menemukan --, geser keluar sampai hanya bagian terakhir yang tersisa ( -d internalparambagian yang datang setelah --). Salah satu cara untuk melakukan ini (menggunakan bashsintaks):

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

Akhirnya, hanya set kedua opsi / argumen yang tersisa, yang bisa Anda sampaikan. Apakah TIDAK menggunakan $*untuk melewati parameter yang tersisa untuk perintah lain. Gunakan "$@"sebagai gantinya, yang mempertahankan pemisahan kata asli.

external_command "$@"
jw013
sumber
Ya terima kasih! Tapi bagaimana tepatnya yang saya temukan --?
highsciguy