Bagaimana saya bisa menambahkan metode bantuan ke skrip shell?

128

Bagaimana cara saya memeriksa apakah suatu -hatribut telah dimasukkan ke dalam skrip shell? Saya ingin menampilkan pesan bantuan saat pengguna menelepon myscript.sh -h.

tttppp
sumber
Contoh yang relevan: stackoverflow.com/questions/14008125/…
Anton Tarasenko

Jawaban:

173

inilah contoh untuk bash:

usage="$(basename "$0") [-h] [-s n] -- program to calculate the answer to life, the universe and everything

where:
    -h  show this help text
    -s  set the seed value (default: 42)"

seed=42
while getopts ':hs:' option; do
  case "$option" in
    h) echo "$usage"
       exit
       ;;
    s) seed=$OPTARG
       ;;
    :) printf "missing argument for -%s\n" "$OPTARG" >&2
       echo "$usage" >&2
       exit 1
       ;;
   \?) printf "illegal option: -%s\n" "$OPTARG" >&2
       echo "$usage" >&2
       exit 1
       ;;
  esac
done
shift $((OPTIND - 1))

Untuk menggunakan ini di dalam suatu fungsi:

  • gunakan "$FUNCNAME"sebagai ganti$(basename "$0")
  • tambahkan local OPTIND OPTARGsebelum menelepongetopts
glenn jackman
sumber
1
Saya mencoba ini di dalam suatu fungsi, tetapi ketika saya mencoba menjalankan fungsinya saya mendapatkan kesalahan ini "basename: invalid option - 'b'". Sepertinya sedang mencoba meneruskan "-bash" ke basenamedengan tanda hubung utama.
Morgan Estes
5
apalagi fungsi gunakan "$FUNCNAME"tidak "$0". Juga, tambahkanlocal OPTIND OPTARG
glenn jackman
Terima kasih. FUNCNAMEbekerja. Saya memiliki semua fungsi saya di dalam satu file, jadi ini sempurna untuk memperluasnya menjadi sesuatu yang bermanfaat bagi orang lain.
Morgan Estes
5
@sigur, pastikan Anda mengutip "$usage" setiap tempat yang Anda gunakan.
glenn jackman
1
Untuk apa shift $((OPTIND - 1))?
hpaknia
45

Argumen pertama ke skrip shell tersedia sebagai variabel $1, sehingga implementasi yang paling sederhana adalah

if [ "$1" == "-h" ]; then
  echo "Usage: `basename $0` [somestuff]"
  exit 0
fi

Tapi apa yang dikatakan anubhava.

seb
sumber
Terima kasih @MarkBooth, kesalahan ketik dikoreksi (ditambah perbaikan dengan membungkus tanda kutip)
seb
Anda harus membiasakan membungkus if dalam [[...]] untuk persyaratan untuk menghindari parsing variabel yang buruk, sumber: github.com/bahamas10/bash-style-guide#bashisms
JREAM
2
Ya, meskipun OP tidak menentukan bash, dan [ini adalah versi yang sesuai dengan POSIX.
seb
Catatan - Untuk menggunakan di dalam function: Anda harus mengganti exit 0dengan returnjika Anda tidak ingin menghentikan shell Anda setelah menjalankan fungsi Anda. (Saya sudah pernah melakukannya sebelumnya)
Illuminator
29

di sini adalah bagian yang saya gunakan untuk memulai server VNC

#!/bin/bash
start() {
echo "Starting vnc server with $resolution on Display $display"
#your execute command here mine is below
#vncserver :$display -geometry $resolution
}

stop() {
echo "Killing vncserver on display $display"
#vncserver -kill :$display
}

#########################
# The command line help #
#########################
display_help() {
    echo "Usage: $0 [option...] {start|stop|restart}" >&2
    echo
    echo "   -r, --resolution           run with the given resolution WxH"
    echo "   -d, --display              Set on which display to host on "
    echo
    # echo some stuff here for the -a or --add-options 
    exit 1
}

################################
# Check if parameters options  #
# are given on the commandline #
################################
while :
do
    case "$1" in
      -r | --resolution)
          if [ $# -ne 0 ]; then
            resolution="$2"   # You may want to check validity of $2
          fi
          shift 2
          ;;
      -h | --help)
          display_help  # Call your function
          exit 0
          ;;
      -d | --display)
          display="$2"
           shift 2
           ;;

      -a | --add-options)
          # do something here call function
          # and write it in your help function display_help()
           shift 2
           ;;

      --) # End of all options
          shift
          break
          ;;
      -*)
          echo "Error: Unknown option: $1" >&2
          ## or call function display_help
          exit 1 
          ;;
      *)  # No more options
          break
          ;;
    esac
done

###################### 
# Check if parameter #
# is set too execute #
######################
case "$1" in
  start)
    start # calling function start()
    ;;
  stop)
    stop # calling function stop()
    ;;
  restart)
    stop  # calling function stop()
    start # calling function start()
    ;;
  *)
#    echo "Usage: $0 {start|stop|restart}" >&2
     display_help

     exit 1
     ;;
esac

Agak aneh bahwa saya menempatkan start stop restart dalam kasus yang terpisah tetapi harus bekerja

Vincent Stans
sumber
jika Anda memberikan opsi kosong ke -d; bukankah itu infinite loop?
zerobane
Mengapa Anda keluar 1 dalam fungsi pembantu?
jeantimex
17

Untuk solusi opsi tunggal cepat, gunakan if

Jika Anda hanya memiliki satu opsi untuk memeriksa dan itu akan selalu menjadi opsi pertama ( $1) maka solusi paling sederhana adalah ifdengan uji ( [). Sebagai contoh:

if [ "$1" == "-h" ] ; then
    echo "Usage: `basename $0` [-h]"
    exit 0
fi

Perhatikan bahwa untuk kompatibilitas posix juga =akan berfungsi ==.

Mengapa mengutip $1?

Alasan $1perlunya dimasukkan dalam tanda kutip adalah bahwa jika tidak ada $1maka shell akan mencoba untuk menjalankan if [ == "-h" ]dan gagal karena ==hanya diberi satu argumen ketika mengharapkan dua:

$ [ == "-h" ]
bash: [: ==: unary operator expected

Untuk penggunaan apa pun yang lebih kompleks getoptataugetopts

Seperti yang disarankan oleh orang lain , jika Anda memiliki lebih dari satu opsi sederhana, atau membutuhkan opsi Anda untuk menerima argumen, maka Anda harus menggunakan kompleksitas tambahan untuk menggunakangetopts .

Sebagai referensi cepat, saya suka tutorial getopts 60 detik .

Anda mungkin juga ingin mempertimbangkan getoptprogram alih-alih shell bawaan getopts. Ini memungkinkan penggunaan opsi panjang, dan opsi setelah argumen non opsi (misalnya, foo a b c --verbosebukan hanya foo -v a b c). Jawaban Stackoverflow ini menjelaskan cara menggunakan GNU getopt.

jeffbyrnes disebutkan bahwa link asli meninggal tapi untungnya mesin jalan kembali telah diarsipkan itu.

Mark Booth
sumber
Terima kasih! Saya telah senang menggunakan getop selama satu tahun sekarang, tapi saya akan melihat getopt juga.
tttppp
1
Sayangnya, tautan ke The 60 Second getopts Tutorial sudah mati; tampaknya bashcurescancer.com tidak lebih. Berikut tautan ke versi Wayback Machine .
jeffbyrnes
-1

saya pikir Anda dapat menggunakan kasing untuk ini ...

case $1 in 
 -h) echo $usage ;; 
  h) echo $usage ;;
help) echo $usage ;;
esac
pengguna baru
sumber