2011-01-03 19 views
18

Tôi đã biết về getopts, và điều này là tốt, nhưng nó là gây phiền nhiễu mà bạn phải có một lá cờ ngay cả đối với các đối số bắt buộc.Làm cách nào để tạo tập lệnh bash có đối số?

Lý tưởng nhất, tôi muốn để có thể có một kịch bản mà nhận lập luận theo hình thức này:

script.sh [optional arguments] [anything required] 

ví dụ

script.sh -rvx output_file.txt 

nơi kịch bản nói rằng bạn cần phải có một đầu ra tập tin. Có cách nào dễ dàng để làm điều này?

Theo như tôi biết, với getopts nó sẽ phải giống như: script.sh -rvx -f output_file.txt, và đó chỉ là không phải là rất sạch sẽ.

Tôi cũng có thể sử dụng trăn nếu cần thiết, nhưng chỉ có 2,4 có sẵn, đó là một chút ngày.

Trả lời

29

Không sử dụng nội trang dựng sẵn, sử dụng getopt (1) thay thế. Họ là (tinh tế) khác nhau và làm những việc khác nhau tốt. Đối với trường hợp của bạn, bạn có thể thực hiện việc này:

#!/bin/bash 

eval set -- $(getopt -n $0 -o "-rvxl:" -- "[email protected]") 

declare r v x l 
declare -a files 
while [ $# -gt 0 ] ; do 
     case "$1" in 
       -r) r=1 ; shift ;; 
       -v) v=1 ; shift ;; 
       -x) x=1 ; shift ;; 
       -l) shift ; l="$1" ; shift ;; 
       --) shift ;; 
       -*) echo "bad option '$1'" ; exit 1 ;; 
       *) files=("${files[@]}" "$1") ; shift ;; 
     esac 
done 

if [ ${#files} -eq 0 ] ; then 
     echo output file required 
     exit 1 
fi 

[ ! -z "$r" ] && echo "r on" 
[ ! -z "$v" ] && echo "v on" 
[ ! -z "$x" ] && echo "x on" 

[ ! -z "$l" ] && echo "l == $l" 

echo "output file(s): ${files[@]}" 

EDIT: cho đầy đủ Tôi đã cung cấp ví dụ về việc xử lý tùy chọn yêu cầu đối số.

+0

Điều này có vẻ như nó thực hiện chính xác những gì tôi muốn. Một câu hỏi với điều này, tuy nhiên: nếu tôi muốn cho phép một lá cờ mà có một đối số (ví dụ, -l file.txt), những gì sẽ là cú pháp? Cảm ơn một lần nữa. –

+0

Tham khảo trang người dùng getopt để biết điều đó. Tóm lại: nối thêm dấu hai chấm vào tùy chọn (ví dụ: '" -rv: x "', yêu cầu v để nhận một đối số). Các tùy chọn dài cũng được hỗ trợ, đó là một cách nó vượt trội hơn các getopts được xây dựng. Lưu ý rằng bạn sẽ phải tự mình xử lý đối số phi tùy chọn bổ sung. – Sorpigal

+0

Cảm ơn bạn rất nhiều. Một phản ứng tuyệt vời. –

11

Nếu bạn đang sử dụng getops, chỉ cần chuyển qua $OPTIND-1 sau tuyên bố trường hợp của bạn. Sau đó, những gì còn lại trong $* sẽ là mọi thứ khác, mà có lẽ là những gì bạn muốn.

shift $((${OPTIND} - 1)); echo "${*}" 
+0

Yup. Chỉ cần kiểm tra $ # để đảm bảo số lượng đối số bắt buộc được thông qua đúng, sau đó truy cập chúng dưới dạng $ 1, $ 2, v.v. như thường lệ. –

4

Bạn đang bị ảo tưởng; sử dụng getopts không yêu cầu đối số bắt buộc được bắt đầu bằng một lá cờ. Tôi đã cố gắng tìm một ví dụ phù hợp từ tập hợp các tập lệnh của tôi; đây là một xấp xỉ bán khá. Nó được gọi là rcsunco và được sử dụng để hủy thanh toán từ RCS. Tôi đã không sửa đổi nó trong một thời gian, tôi thấy; Tôi sử dụng nó khá thường xuyên (vì tôi chưa di chuyển hoàn toàn từ RCS).

#!/bin/sh 
# 
# "@(#)$Id: rcsunco.sh,v 2.1 2002/08/03 07:41:00 jleffler Exp $" 
# 
# Cancel RCS checkout 

# -V print version number 
# -n do not remove or rename checked out file (like SCCS unget) (default) 
# -r remove checked out file (default) 
# -k keep checked out file as $file.keep 
# -g checkout (unlocked) file after clean-up 
# -q quiet checkout 

: ${RCS:=rcs} 
: ${CO:=co} 

remove=yes 
keep=no 
get=no 
quiet= 

while getopts gknqrV opt 
do 
    case $opt in 
    V) echo "`basename $0 .sh`: RCSUNCO Version $Revision: 2.1 $ ($Date: 2002/08/03 07:41:00 $)" | 
     rcsmunger 
     exit 0;; 
    g) get=yes;; 
    k) keep=yes;; 
    n) remove=no;; 
    q) quiet=-q;; 
    r) remove=yes;; 
    *) echo "Usage: `basename $0 .sh` [-{n|g}][-{r|k}] file [...]" 1>&2 
     exit 1;; 
    esac 
done 

shift $(($OPTIND-1)) 

for file in $* 
do 
    rfile=$(rfile $file) 
    xfile=$(xfile $rfile) 
    if $RCS -u $rfile 
    then 
     if [ $keep = yes ] 
     then 
      if [ -f $xfile ] 
      then 
       mv $xfile $xfile.keep 
       echo "$xfile saved in $xfile.keep" 
      fi 
     elif [ $remove = yes ] 
     then rm -f $xfile 
     fi 
     if [ $get = yes ] && [ $remove = yes -o $keep = yes ] 
     then $CO $quiet $rfile 
     fi 
    fi 
done 

Nó chỉ là một xấp xỉ bán gần đúng; kịch bản lặng lẽ không làm gì nếu bạn không cung cấp bất kỳ tên tệp nào sau các đối số tùy chọn. Tuy nhiên, nếu bạn cần, bạn có thể kiểm tra xem các đối số bắt buộc có xuất hiện sau 'thay đổi' hay không. Một kịch bản khác của tôi không có đối số bắt buộc. Nó chứa:

... 
shift $(($OPTIND - 1)) 

case $# in 
2) case $1 in 
    install) MODE=Installation;; 
    uninstall) MODE=Uninstallation;; 
    *)   usage;; 
    esac;; 
*) usage;; 
esac 

Vì vậy, rằng lệnh (jlss) có thể mất đối số tùy chọn như -d $HOME, nhưng đòi hỏi một trong hai install hoặc uninstall theo sau là tên của một cái gì đó để cài đặt. Phương thức cơ bản về sử dụng là:

jlss install program 

Nhưng chế độ tùy chọn là:

jlss -d $HOME -u me -g mine -x -p install program 

Tôi không hiển thị tất cả jlss bởi vì nó có khoảng 12 tùy chọn - nó không phải là nhỏ gọn như rcsunco .


Nếu bạn đang đối phó với đối số bắt buộc trước khi đối số tùy chọn, sau đó bạn sẽ phải làm một chút công việc:

  • Bạn muốn nhận các đối số bắt buộc, chuyển chúng ra khỏi đường.
  • Sau đó, bạn xử lý các đối số tùy chọn bằng cờ.
  • Cuối cùng, nếu thích hợp, bạn xử lý thêm đối số 'tên tệp'.

Nếu bạn đang đối phó với các đối số bắt buộc xen kẽ với các đối số tùy chọn (cả trước và sau các đối số bắt buộc), thì bạn vẫn còn nhiều việc phải làm. Điều này được sử dụng bởi nhiều hệ thống VCS; CVS và GIT đều có cơ sở:

git -global option command [-sub option] [...] 

Ở đây, bạn chạy một vòng getopts để nhận các tùy chọn toàn cầu; lấy các đối số bắt buộc; và chạy vòng lặp getopts thứ hai để nhận các tùy chọn phụ (và có thể chạy vòng lặp cuối cùng qua đối số 'tên tệp').

Không phải cuộc sống vui vẻ phải không?

2

Và tôi nghe thấy một điều hoàn toàn ngược lại, rằng bạn không nên sử dụng getopt, nhưng nội dung dựng sẵn getopts.

Cross-platform getopt for a shell script

bao giờ sử dụng getopt (1). getopt không thể xử lý chuỗi đối số trống hoặc tham số với khoảng trắng được nhúng. Vui lòng quên rằng nó đã từng tồn tại .

Vỏ POSIX (và các loại khác) cung cấp các thiết bị an toàn sử dụng an toàn để sử dụng thay thế.

Các vấn đề liên quan