Bagaimana saya bisa mendeteksi bahwa tidak ada opsi yang diteruskan dengan getop?

19

Saya punya kode ini -

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
done
print 'hi'$name

Ketika saya menjalankan bash getoptDemos.sh(tanpa opsi) itu mencetak hibukannya memanggil fungsi usage. Itu panggilan penggunaan ketika opsi selain w, h dan l diberikan. Maka tidak bisa bekerja ketika tidak ada opsi yang ditentukan.

Saya telah mencoba menggunakan ?, \?, :di tempat *tapi aku tidak bisa mencapai apa yang saya ingin. Maksud saya semua docspada getoptmengatakan itu untuk digunakan ?.

Apa yang saya lakukan salah?

Hussain Tamboli
sumber
Apa yang Anda jalankan di bawah shell?
Julian
Saya menjalankannya di bawah/bin/bash
Hussain Tamboli

Jawaban:

15

Ketika Anda menjalankan skrip ini tanpa opsi apa pun, getopt akan mengembalikan false, sehingga tidak akan masuk loop sama sekali. Ini hanya akan drop down ke cetakan - apakah ini ksh / zsh?

Jika Anda harus memiliki opsi, Anda sebaiknya menguji $ name setelah loop.

if [ -z "$name" ]
then
   usage
   exit
fi

Tetapi pastikan $namekosong sebelum memanggil getopts(karena mungkin ada $namedi lingkungan shell diterima pada startup) dengan

unset name

(sebelum getoptsloop)

Julian
sumber
tidak. pesta Jadi, bagaimana saya mencapai apa yang saya inginkan - menangani no argumentkondisi menggunakan bash.
Hussain Tamboli
Jika Anda ingin opsi wajib, saya tidak berpikir itu mungkin - itu mungkin mengapa mereka disebut opsi :) Anda dapat menguji $ name, setelah loop untuk memastikan itu telah ditetapkan. jika [-z "$ name"]; lalu penggunaan; keluar ; fi
Julian
Terima kasih. kode di atas sangat membantu. Sayang getoptssekali tidak memiliki ketentuan seperti itu. Apa yang lebih buruk dari itu tidak bisa membuat Anda marah.
Hussain Tamboli
bagaimana jika saya menjalankan shell lain? zsh, sh. apakah ada shell selain bash yang menangani kondisi ini?
Hussain Tamboli
20

getoptsmemproses opsi pada gilirannya. Itu tugasnya. Jika pengguna kebetulan tidak memberikan opsi, permintaan pertama getoptskeluar dari loop sementara.

Jika tidak ada opsi yang mengambil argumen, nilai OPTINDmenunjukkan berapa banyak opsi yang dilewati. Secara umum, OPTINDadalah jumlah argumen yang merupakan opsi atau argumen untuk opsi, yang bertentangan dengan argumen non-opsi (operan).

while getopts …; do …; done
if [ $OPTIND -eq 1 ]; then echo "No options were passed"; fi
shift $((OPTIND-1))
echo "$# non-option arguments"

Bagaimanapun, Anda tidak mencoba menentukan apakah tidak ada opsi, tetapi apakah tidak ada nameopsi-pengaturan yang dilewati. Jadi periksa apakah nametidak disetel (dan berhati-hatilah untuk membatalkannya terlebih dahulu) .

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1
Terima kasih. +1 untuk Anda. ketika saya meletakkan 3 baris terakhir dari kode Anda di sample.sh dan jalankan bash sample.sh -abc file.txtitu memberi - 1 non-option arguments. bagaimana cara mengetahui berapa banyak opsi yang diberikan. (di sini 3)
Hussain Tamboli
1
Aneh tidak ada yang mengomentari sedikit bug ini - jika tidak ada opsi yang diberikan, OPTIND akan menjadi 1 setelah loop 'while getopts ...'. Jadi, jika cek harus memeriksa kesetaraan dengan 1, bukan nol.
Daniel
4

Jika skrip Anda harus menerima argumen opsi, letakkan blok ini di awal (sebelum getops).

if [[ ! $@ =~ ^\-.+ ]]
then
  #display_help;
fi

Block memeriksa bahwa string parameter tidak diawali dengan -simbol, yang menunjukkan bahwa parameter pertama bukanlah argumen opsi.

mcounad
sumber
2

Saya akan memeriksanya dengan variabel. Jika getopts tidak pernah melewati loop jika tidak ada argumen, Anda dapat menggunakannya misalnya seperti ini:

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}

no_args="true"
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
    no_args="false"
done

[[ "$no_args" == "true" ]] && { usage; exit 1; }

print 'hi'$name
Imre Kneifel
sumber
0

Tepat sebelum getoptsblok Anda , periksa untuk melihat apakah $1(argumen / opsi pertama yang Anda berikan pada baris perintah) sama dengan string kosong. Jika ya, cetak pesan penggunaan dan keluar, (atau jalankan beberapa fungsi "tidak ada opsi" jika Anda seorang anarkis), jika tidak biarkan getoptsmengurai opsi seperti biasa.

Alasan fitur ini tidak termasuk dalam getopts, adalah karena Anda sudah dapat menyelesaikannya di bash dengan "jika-lain". Contoh:

if [[ $1 == "" ]]; then
    Your_Usage_Function;
    exit;
else
   #parse options with getopts code block here;
fi

Masuk akal?

codrcodz
sumber