Kiểm tra xem có bất kỳ tham số nào trong tập lệnh bash khớp với chuỗi không


67

Tôi đang cố gắng viết một tập lệnh mà tôi muốn kiểm tra xem có bất kỳ tham số nào được truyền cho tập lệnh bash khớp với một chuỗi không. Cách tôi thiết lập ngay bây giờ là

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

nhưng có thể có một số lượng lớn các tham số, vì vậy tôi đã tự hỏi liệu có cách nào tốt hơn để làm điều này không?

Cảm ơn

EDIT: Tôi đã thử đoạn mã này và gọi kịch bản với tùy chọn, -disableVenusBld, nhưng nó vẫn in ra "Bắt đầu xây dựng". Tôi có làm điều gì sai? Cảm ơn trước!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi

Cảm ơn các bạn đã trả lời, tôi đánh giá cao bạn sẽ dành thời gian để giúp tôi. Tôi đã thử một đoạn mã, nhưng dường như tôi không thể hiểu được chuyện gì đang xảy ra. Có ý kiến ​​gì không? (Tôi đã dán mã trong bản chỉnh sửa bài đăng gốc của mình)
iman453

Hmm: nó làm việc cho tôi Tôi đã thêm vào #! /bin/sh -đầu những gì bạn đã đưa vào đó, làm cho tập lệnh có thể thực thi được, sau đó ./t.shin "Bắt đầu xây dựng", nhưng ./t.sh -disableVenusBldkhông in gì cả.
Norman Gray

Câu trả lời:


59

Có vẻ như bạn đang xử lý tùy chọn trong tập lệnh shell. Đây là thành ngữ cho điều đó:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(Có một vài quy ước để thụt lề ;;và một số shell cho phép bạn đưa ra các tùy chọn như (--opt1), để giúp khớp nối niềng răng, nhưng đây là ý tưởng cơ bản)


3
Một shiftcâu lệnh được sử dụng khi không biết trước số lượng đối số của một lệnh, khi người dùng có thể đưa ra bao nhiêu đối số tùy thích. Trong các trường hợp như vậy, các đối số được xử lý trong một whilevòng lặp với điều kiện kiểm tra là $#. Điều kiện này đúng với số lượng đối số lớn hơn 0. Các $1biến và shifttuyên bố xử lý mỗi đối số. Số lượng đối số được giảm mỗi lần shiftđược thực thi và cuối cùng trở thành số không, khi đó whilevòng lặp thoát. nguồn
Serge Stroobandt

Dưới đây là một ví dụ tương tự với echo $1 | sedxử lý giá trị đối số bổ sung .
Serge Stroobandt

26

Điều này làm việc cho tôi. Nó thực hiện chính xác những gì bạn yêu cầu và không có gì nữa (không xử lý tùy chọn). Cho dù đó là tốt hay xấu là một bài tập cho người đăng :)

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

Điều này đem đến xử lý đặc biệt của $* và bash siêu thử nghiệm [[... ]]dấu ngoặc đơn.


2
IMHO đây phải là câu trả lời đúng nhất, vì câu hỏi chỉ yêu cầu kiểm tra sự hiện diện của một tham số. Tôi đã chỉnh sửa, tuy nhiên, thay đổi $*thành $@, vì chuỗi cần kiểm tra có thể có khoảng trắng và thêm liên kết đến tài liệu của bash về nó.
h7r

9
Ý của bạn là sử dụng toán tử = ~? Mặt khác, tôi không thấy lý do tại sao điều này nên hoạt động và thực sự nó không hoạt động khi tôi thử kịch bản chính xác.
Seppo Enarvi 14/07/2015

3
Không làm việc. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia

2
Điều này so sánh toàn bộ danh sách đối số với your string. Tôi nghĩ bạn cần phải làm những gì được đề xuất bởi câu trả lời này . tức là: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar foosẽ làm việc
starfry

2
Câu trả lời này đã sai trong bốn năm qua vì chỉnh sửa của h7r đã phá vỡ nó. Câu trả lời ban đầu (mà tôi đã khôi phục) hoạt động, cung cấp cho chuỗi của bạn, không có ký tự toàn cầu và với một số thông tin sai. Ví dụ: nếu lệnh là create a new certificatevà chuỗi chuỗi của bạn cat, thì điều này sẽ báo cáo một trận đấu vì certificate có chứa cat .
Scott

8

Cách tìm kiếm (với ký tự đại diện) toàn bộ không gian tham số:

if [[ $@ == *'-disableVenusBld'* ]]
then

Chỉnh sửa: Ok, ok, vì vậy đó không phải là một câu trả lời phổ biến. Còn cái này thì sao, nó hoàn hảo!:

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2: Ok, ok, có lẽ điều này không hoàn hảo ... Hãy nghĩ rằng nó chỉ hoạt động nếu -param ở đầu danh sách và cũng sẽ khớp với -paramXZY hoặc -paramABC. Tôi vẫn nghĩ rằng vấn đề ban đầu có thể được giải quyết rất độc đáo bằng thao tác chuỗi bash, nhưng tôi chưa hoàn toàn bẻ khóa nó ở đây ... -Có thể không ??


Đề xuất thứ hai của bạn - so sánh thay thế lọc với thay thế hoàn toàn - hoạt động hợp lý và có ưu điểm là không phá vỡ danh sách các đối số.
Donal Fellows

Bạn có thể giải thích những gì gợi ý thứ hai (đặc biệt ${@#) không?
Velop

1
@velop Chắc chắn rồi! Vì vậy, bạn biết đó $@là một biến đặc biệt chứa tất cả các đối số dòng lệnh? Chà, tôi vừa sử dụng thao tác chuỗi Bash trên biến đó để loại bỏ chuỗi con "-disableVenusBld", và sau đó tôi so sánh nó với ban đầu $@. Vì vậy, nếu $@bằng nhau -foo -barthì ${@#-disableVenusBld}vẫn -foo -barvậy, vì vậy tôi có thể thấy rằng lá cờ tôi đang tìm không có mặt. Tuy nhiên, nếu $@bằng -foo -disableVenusBld -barthì ${@#-disableVenusBld}sẽ -foo -barkhông bằng $@, do đó cho tôi biết rằng lá cờ tôi đang tìm là có mặt! Thật tuyệt
Giàu

@velop Tìm hiểu thêm về thao tác chuỗi Bash tại đây: tldp.org/LDP/abs/html/opes-manipulation.html
Rich

@Rich khá gọn gàng ^^, thx cho lời giải thích.
Velop

4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Nếu bạn chỉ cần kiểm tra các tham số bắt đầu tại $3, hãy thực hiện tìm kiếm trong một hàm:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

Nhưng tôi tự hỏi tại sao bạn lại cố gắng làm điều này ngay từ đầu, đó không phải là nhu cầu chung. Thông thường, bạn sẽ xử lý các tùy chọn theo thứ tự, như trong câu trả lời của Dennis cho câu hỏi trước đó của bạn .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.