2009-03-31 8 views
78

Tôi đã đưa ra một thông số cơ bản để giúp tự động hóa quy trình xóa một số thư mục khi chúng không cần thiết.Xác thực tham số cho tập lệnh Bash

#!/bin/bash 
rm -rf ~/myfolder1/$1/anotherfolder 
rm -rf ~/myfolder2/$1/yetanotherfolder 
rm -rf ~/myfolder3/$1/thisisafolder 

này được gợi lên như vậy:

./myscript.sh <{id-number}> 

Vấn đề là nếu bạn quên gõ vào id-number(như tôi đã làm rồi), sau đó nó có thể có khả năng xóa rất nhiều những thứ mà bạn thực sự không muốn xóa.

Có cách nào bạn có thể thêm bất kỳ hình thức xác thực nào vào thông số dòng lệnh không? Trong trường hợp của tôi, nó sẽ là tốt để kiểm tra xem a) có một tham số, b) đó là số, và c) thư mục đó tồn tại; trước khi tiếp tục với tập lệnh.

Trả lời

129
#!/bin/sh 
die() { 
    echo >&2 "[email protected]" 
    exit 1 
} 

[ "$#" -eq 1 ] || die "1 argument required, $# provided" 
echo $1 | grep -E -q '^[0-9]+$' || die "Numeric argument required, $1 provided" 

while read dir 
do 
    [ -d "$dir" ] || die "Directory $dir does not exist" 
    rm -rf "$dir" 
done <<EOF 
~/myfolder1/$1/anotherfolder 
~/myfolder2/$1/yetanotherfolder 
~/myfolder3/$1/thisisafolder 
EOF 

chỉnh sửa: Tôi bị mất một phần về việc kiểm tra nếu các thư mục tồn tại đầu tiên, vì vậy tôi nói thêm rằng trong, hoàn thành kịch bản. Ngoài ra, đã giải quyết các vấn đề được nêu ra trong các nhận xét; cố định cụm từ thông dụng, chuyển từ == thành eq.

Đây phải là tập lệnh tuân thủ POSIX di động theo như tôi có thể biết; nó không sử dụng bất kỳ bashisms, mà thực sự quan trọng bởi vì /bin/sh trên Ubuntu thực sự là dash những ngày này, không phải bash.

+1

như nó cho độ nhỏ gọn – ojblass

+0

nhớ đặt + e và sử dụng '-eq' thay vì '==' để so sánh số nguyên – guns

+0

Thay đổi thành -eq; những gì đặt + e mua cho bạn ở đây? –

7

Sử dụng '-z' để kiểm tra các chuỗi trống và '-d để kiểm tra thư mục.

if [[ -z "[email protected]" ]]; then 
    echo >&2 "You must supply an argument!" 
    exit 1 
elif [[ ! -d "[email protected]" ]]; then 
    echo >&2 "[email protected] is not a valid directory!" 
    exit 1 
fi 
+1

tại sao bạn cần tăng gấp đôi [[]]? – vehomzzz

10

Không như đạn là câu trả lời ở trên, tuy nhiên vẫn có hiệu lực:

#!/bin/bash 
if [ "$1" = "" ] 
then 
    echo "Usage: $0 <id number to be cleaned up>" 
    exit 
fi 

# rm commands go here 
5

Người đàn ông trang cho thử nghiệm (man test) cung cấp tất cả các nhà khai thác có sẵn, bạn có thể sử dụng các toán như boolean trong bash. Sử dụng những lá cờ đó trong phần đầu của kịch bản (hoặc các hàm) để xác thực đầu vào giống như bạn làm trong bất kỳ ngôn ngữ lập trình nào khác. Ví dụ:

if [ -z $1 ] ; then 
    echo "First parameter needed!" && exit 1; 
fi 

if [ -z $2 ] ; then 
    echo "Second parameter needed!" && exit 2; 
fi 
13

Tôi sẽ sử dụng bash của [[:

if [[ ! ("$#" == 1 && $1 =~ ^[0-9]+$ && -d $1) ]]; then 
    echo 'Please pass a number that corresponds to a directory' 
    exit 1 
fi 

tôi thấy this faq là một nguồn thông tin tốt.

+0

'faq này' phục sinh :) –

20

Giải pháp sh bởi Brian Campbell, trong khi cao quý và được thực hiện tốt, có một số vấn đề, vì vậy tôi nghĩ mình sẽ cung cấp giải pháp bash của riêng mình.

Những vấn đề với sh một:

  • Các dấu ngã trong ~/foo không mở rộng đến homedirectory của bạn bên trong heredocs. Và cả khi được đọc bởi câu lệnh read hoặc được trích dẫn trong câu lệnh rm. Điều này có nghĩa là bạn sẽ gặp phải các lỗi No such file or directory.
  • Ngã ba grep và các hoạt động cơ bản như vậy là không chính xác. Đặc biệt là khi bạn đang sử dụng một vỏ crappy để tránh trọng lượng "nặng" của bash.
  • Tôi cũng nhận thấy một số vấn đề về trích dẫn, ví dụ xung quanh việc mở rộng tham số trong số echo của anh ấy.
  • Trong khi hiếm, giải pháp không thể đối phó với tên tệp có chứa dòng mới. (Hầu như không có giải pháp nào trong số sh có thể đối phó với chúng - đó là lý do tại sao tôi hầu như luôn thích bash, nó càng bị lỗi nhiều hơn & để khai thác khi sử dụng tốt).

Trong khi, có, sử dụng /bin/sh cho hashbang của bạn có nghĩa là bạn phải tránh bash chủ nghĩa ở tất cả các chi phí, bạn có thể sử dụng tất cả các bash chủ nghĩa mà bạn thích, ngay cả trên Ubunutu hoặc không có điều gì khi bạn chân thành và đưa #!/bin/bash tại hàng đầu.

Vì vậy, đây là giải pháp bash nhỏ hơn, sạch hơn, minh bạch hơn, có thể "nhanh hơn" và chống đạn hơn.

[[ -d $1 && $1 != *[^0-9]* ]] || { echo "Invalid input." >&2; exit 1; } 
rm -rf ~/foo/"$1"/bar ... 
  1. Chú ý các dấu ngoặc kép quanh $1 trong báo cáo rm!
  2. Kiểm tra -d cũng sẽ không thành công nếu $1 trống, vì vậy đó là hai lần kiểm tra trong một.
  3. Tôi tránh các cụm từ thông dụng vì một lý do. Nếu bạn phải sử dụng =~ trong bash, bạn nên đặt cụm từ thông dụng vào một biến. Trong mọi trường hợp, những quả bóng như của tôi luôn thích hợp hơn và được hỗ trợ trong các phiên bản bash hơn.
+1

Vì vậy, là mảnh globbing '$ 1! = * [^ 0-9] *' bash cụ thể sau đó? – grinch

4

Bạn có thể xác nhận điểm a và điểm b gọn bằng cách làm một cái gì đó như sau:

#!/bin/sh 
MYVAL=$(echo ${1} | awk '/^[0-9]+$/') 
MYVAL=${MYVAL:?"Usage - testparms <number>"} 
echo ${MYVAL} 

nào cho chúng ta ...

$ ./testparams.sh 
Usage - testparms <number> 

$ ./testparams.sh 1234 
1234 

$ ./testparams.sh abcd 
Usage - testparms <number> 

Phương pháp này sẽ làm việc tốt trong sh.

6

Sử dụng set -u điều này sẽ gây ra bất kỳ tham chiếu đối số không được đặt nào để ngay lập tức thất bại tập lệnh.

http://www.davidpashley.com/articles/writing-robust-shell-scripts.html

+0

Cảm ơn bạn đã liên kết bài viết! –

+0

Đây là một sửa chữa dễ dàng trong nhiều trường hợp và hoạt động cho các chức năng. Cảm ơn! –

1

Bài đăng cũ nhưng tôi nghĩ tôi có thể đóng góp.

Một tập lệnh được cho là không cần thiết và với một số dung sai đối với thẻ hoang dã có thể được thực hiện từ dòng lệnh.

  1. kết hợp mọi nơi hoang dã. Cho phép loại bỏ bất kỳ sự xuất hiện của phụ "thư mục"

  2. Shell lặp. Cho phép loại bỏ trước và sau khi thư mục cụ thể với một dòng

    $ rm -rf ~/foo{1,2,3}/folder/{ab,cd,ef} 
    
  3. Shell lặp + var (BASH thử nghiệm).

    $ var=bar rm -rf ~/foo{1,2,3}/${var}/{ab,cd,ef}