getopt
và getopts
là những con thú khác nhau, và mọi người dường như có một chút hiểu lầm về những gì họ làm. getopts
là một lệnh tích hợp bash
để xử lý các tùy chọn dòng lệnh trong một vòng lặp và lần lượt gán từng tùy chọn và giá trị tìm thấy cho các biến tích hợp, do đó bạn có thể xử lý chúng thêm. getopt
tuy nhiên, là một chương trình tiện ích bên ngoài và nó không thực sự xử lý các tùy chọn của bạn cho bạn theo cách mà ví dụ như bash getopts
, Getopt
mô-đun Perl hoặc Python optparse
/ argparse
mô-đun làm. Tất cả những gì getopt
làm là hợp thức hóa các tùy chọn được truyền vào - tức là chuyển đổi chúng sang dạng chuẩn hơn, để kịch bản shell xử lý chúng dễ dàng hơn. Ví dụ: một ứng dụng getopt
có thể chuyển đổi như sau:
myscript -ab infile.txt -ooutfile.txt
vào đây:
myscript -a -b -o outfile.txt infile.txt
Bạn phải tự xử lý thực tế. Bạn hoàn toàn không phải sử dụng getopt
nếu bạn thực hiện nhiều hạn chế khác nhau về cách bạn có thể chỉ định các tùy chọn:
- chỉ đặt một tùy chọn cho mỗi đối số;
- tất cả các tùy chọn đi trước bất kỳ tham số vị trí nào (tức là đối số không phải tùy chọn);
- đối với các tùy chọn có giá trị (ví dụ
-o
ở trên), giá trị phải đi như một đối số riêng biệt (sau một khoảng trắng).
Tại sao sử dụng getopt
thay vì getopts
? Lý do cơ bản là chỉ GNU getopt
cung cấp cho bạn hỗ trợ cho các tùy chọn dòng lệnh được đặt tên dài. 1 (GNU getopt
là mặc định trên Linux. Mac OS X và FreeBSD đi kèm với một cơ bản và không hữu ích lắm getopt
, nhưng phiên bản GNU có thể được cài đặt; xem bên dưới.)
Ví dụ: đây là một ví dụ về việc sử dụng GNU getopt
, từ một tập lệnh của tôi được gọi là javawrap
:
# NOTE: This requires GNU getopt. On Mac OS X and FreeBSD, you have to install this
# separately; see below.
TEMP=`getopt -o vdm: --long verbose,debug,memory:,debugfile:,minheap:,maxheap: \
-n 'javawrap' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
VERBOSE=false
DEBUG=false
MEMORY=
DEBUGFILE=
JAVA_MISC_OPT=
while true; do
case "$1" in
-v | --verbose ) VERBOSE=true; shift ;;
-d | --debug ) DEBUG=true; shift ;;
-m | --memory ) MEMORY="$2"; shift 2 ;;
--debugfile ) DEBUGFILE="$2"; shift 2 ;;
--minheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MinHeapFreeRatio=$2"; shift 2 ;;
--maxheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MaxHeapFreeRatio=$2"; shift 2 ;;
-- ) shift; break ;;
* ) break ;;
esac
done
Điều này cho phép bạn chỉ định các tùy chọn như --verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"
hoặc tương tự. Tác dụng của lệnh gọi getopt
là hợp thức hóa các tùy chọn để --verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"
bạn có thể dễ dàng xử lý chúng hơn. Việc trích dẫn xung quanh "$1"
và "$2"
rất quan trọng vì nó đảm bảo rằng các đối số có khoảng trắng trong chúng được xử lý đúng cách.
Nếu bạn xóa 9 dòng đầu tiên (mọi thứ qua eval set
dòng), mã sẽ vẫn hoạt động ! Tuy nhiên, mã của bạn sẽ được lựa chọn nhiều hơn trong các loại tùy chọn mà nó chấp nhận: Cụ thể, bạn sẽ phải chỉ định tất cả các tùy chọn trong biểu mẫu "chính tắc" được mô tả ở trên. getopt
Tuy nhiên, với việc sử dụng , bạn có thể nhóm các tùy chọn một chữ cái, sử dụng các hình thức tùy chọn dài không mơ hồ ngắn hơn, sử dụng --file foo.txt
hoặc --file=foo.txt
kiểu, sử dụng -m 4096
hoặc -m4096
kiểu, trộn tùy chọn và không tùy chọn theo bất kỳ thứ tự nào, v.v. getopt
cũng đưa ra một thông báo lỗi nếu không tìm thấy tùy chọn không rõ ràng hoặc mơ hồ.
LƯU Ý : Thực tế có hai phiên bản hoàn toàn khác nhaugetopt
, cơ bản getopt
và GNU getopt
, với các tính năng khác nhau và các quy ước gọi khác nhau. 2 Basic getopt
khá bị hỏng: Không chỉ không xử lý các tùy chọn dài, thậm chí nó còn không thể xử lý các không gian được nhúng bên trong các đối số hoặc đối số trống, trong khi đó getopts
thực hiện đúng. Các mã trên sẽ không hoạt động trong cơ bản getopt
. GNU getopt
được cài đặt theo mặc định trên Linux, nhưng trên Mac OS X và FreeBSD, nó cần được cài đặt riêng. Trên Mac OS X, cài đặt MacPorts ( http://www.macports.org ) và sau đó thực hiện sudo port install getopt
để cài đặt GNU getopt
(thường vào /opt/local/bin
) và đảm bảo rằng đó /opt/local/bin
là trong đường dẫn shell của bạn trước/usr/bin
. Trên FreeBSD, cài đặt misc/getopt
.
Hướng dẫn nhanh để sửa đổi mã ví dụ cho chương trình của riêng bạn: Trong vài dòng đầu tiên, tất cả là "mẫu soạn sẵn" nên giữ nguyên, ngoại trừ dòng gọi getopt
. Bạn nên thay đổi tên chương trình sau -n
, chỉ định các tùy chọn ngắn sau -o
và tùy chọn dài sau --long
. Đặt dấu hai chấm sau các tùy chọn có giá trị.
Cuối cùng, nếu bạn thấy mã chỉ set
thay vì eval set
, nó được viết cho BSD getopt
. Bạn nên thay đổi nó để sử dụng eval set
kiểu, hoạt động tốt với cả hai phiên bản getopt
, trong khi đồng bằng set
không hoạt động đúng với GNU getopt
.
1 Trên thực tế, getopts
trong ksh93
hỗ trợ các tùy chọn được đặt tên dài, nhưng lớp vỏ này không được sử dụng thường xuyên như bash
. Trong zsh
, sử dụng zparseopts
để có được chức năng này.
2 Về mặt kỹ thuật, "GNU getopt
" là một cách viết sai; phiên bản này thực sự được viết cho Linux chứ không phải là dự án GNU. Tuy nhiên, nó tuân theo tất cả các quy ước GNU và thuật ngữ "GNU getopt
" thường được sử dụng (ví dụ trên FreeBSD).