2011-02-03 45 views
8
$myscript.sh -host blah -user blah -pass blah 

Tôi muốn chuyển đối số vào đó.Phân tích cú pháp đối số tập lệnh shell

Tôi đang sử dụng để làm $1, $2, $3 .... nhưng tôi muốn bắt đầu đặt tên cho chúng

+2

Xem xét các tùy chọn không phân luồng nhưng chuyển các giá trị thông qua môi trường: ví dụ: "host = hostname user = me myscript.sh" –

+0

trùng lặp của http://stackoverflow.com/questions/192249/how-do-i-parse-command -line-arguments-in-bash, có một câu trả lời rất hay so sánh 'bash',' getopts' (built-in shell) và 'getopt' (không được khuyến nghị trừ khi nó là phiên bản util-linux và bạn sử dụng nó) các tính năng không phải POSIX để tránh các vấn đề với arg trống, v.v.) –

Trả lời

13

Có rất nhiều cách để phân tích lập luận trong sh. Getopt là tốt. Dưới đây là một kịch bản đơn giản mà phân tích mọi thứ bằng tay:

#!/bin/sh 

while echo $1 | grep -q ^-; do 
    eval $(echo $1 | sed 's/^-//')=$2 
    shift 
    shift 
done 

echo host = $host 
echo user = $user 
echo pass = $pass 
echo args = [email protected] 

Một chạy mẫu trông giống như:

$ ./a.sh -host foo -user me -pass secret some args 
host = foo 
user = me 
pass = secret 
args = some args 

Lưu ý rằng đây không phải là thậm chí từ xa mạnh mẽ và ồ ạt mở đối với an ninh lỗ kể từ khi một kịch bản eval của chuỗi được xây dựng bởi người dùng. Nó chỉ là có nghĩa là để phục vụ như là một ví dụ cho một cách có thể để làm việc. Một phương pháp đơn giản hơn là yêu cầu người dùng chuyển dữ liệu trong môi trường. Trong một vỏ bourne (ví dụ, bất cứ điều gì đó không phải là trong gia đình csh):

$ host=blah user=blah pass=blah myscript.sh 

hoạt động độc đáo, và các biến $host, $user, $pass sẽ có sẵn trong kịch bản.

#!/bin/sh 
echo host = ${host:?host empty or unset} 
echo user = ${user?user not set} 
... 
+2

Sử dụng 'declare' thay vì' eval' sẽ an toàn hơn. –

+0

Ngoài đề xuất của @ DennisWilliamson, tôi khuyên bạn nên xóa '| tr -d '\ 012'', vì nó không cần thiết - việc thay thế lệnh tự động trims tất cả các dòng mới. – mklement0

+0

@ mklement0 Tôi tin rằng tôi đã thực sự có ý thức suy nghĩ về dòng mới nội bộ, đó là lẻ xem xét rằng cố gắng để đối phó với đó là một nỗ lực để thêm mạnh mẽ cho một ý tưởng đó là vô lý mong manh. Có rất nhiều cách rất dễ vỡ, nó quá buồn cười. –

9
+0

@Zac tốt, cảm ơn. –

+1

Lưu ý rằng 'getopts' là một nội trang Bash trong khi' getopt' là một tiện ích bên ngoài. Công cụ trước chỉ hoạt động với các tùy chọn ngắn (ví dụ: '-e') trong khi tùy chọn sau cũng sẽ hoạt động với các tùy chọn dài (ví dụ:' -foo'). Lưu ý rằng có một số [vấn đề] (http://mywiki.wooledge.org/BashFAQ/035) mà sau này phải được giải quyết (các phiên bản sau của 'getopt' có ít vấn đề hơn). –

6

Đây là một cách đơn giản để xử lý tùy chọn cả dài và ngắn:

while [[ $1 == -* ]]; do 
    case "$1" in 
     -h|--help|-\?) show_help; exit 0;; 
     -v|--verbose) verbose=1; shift;; 
     -f) if (($# > 1)); then 
      output_file=$2; shift 2 
      else 
      echo "-f requires an argument" 1>&2 
      exit 1 
      fi ;; 
     --) shift; break;; 
     -*) echo "invalid option: $1" 1>&2; show_help; exit 1;; 
    esac 
done 

Từ How can I handle command-line arguments (options) to my script easily?

+1

+1; tuy nhiên, lưu ý rằng điều này sẽ không xử lý các tùy chọn _compressed_, chẳng hạn như '-vf' để biểu diễn' -v -f'. – mklement0

0

giả đã sử dụng trên William Pursell dụ (với lời khuyên Dennis Williamson) cho các thông số ở định dạng này : tập lệnh -param1 = value1 -param2 = value2 ...

Đây là mã với trình phân tích cú pháp đối số một dòng (lưu nó trong tệp 'tập lệnh') :

#!/bin/bash 

while echo $1 | grep ^- > /dev/null; do declare $(echo $1 | sed 's/-//g' | sed 's/=.*//g' | tr -d '\012')=$(echo $1 | sed 's/.*=//g' | tr -d '\012'); shift; done 

echo host = $host 
echo user = $user 
echo pass = $pass 

Bạn gọi nó là như thế:

script -host=aaa -user=bbb -pass=ccc

và kết quả là

host = aaa 
user = bbb 
pass = ccc 

Đừng ai biết mã ngắn hơn để phân tích lý lẽ hơn thế này ở trên không?

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