Trường hợp rơi vào trường hợp nếu điều kiện


11

Tôi đang tìm kiếm một cách để có sự sụp đổ xảy ra dựa trên một điều kiện if trong một điều kiện trường hợp trong bash. Ví dụ:

input="foo"
VAR="1"

case $input in
foo)
    if [ $VAR = "1" ]; then

        # perform fallthrough

    else

        # do not perform fallthrough

    fi
;;
*)
    echo "fallthrough worked!"
;;
esac

Trong đoạn mã trên, nếu biến VAR1, tôi muốn có điều kiện trường hợp thực hiện dự phòng.


1
Câu hỏi nhỏ: Bạn đang cố gắng nhảy từ if [ $VAR -eq 1 ]; thenmột phần của mã sang bất cứ thứ gì trong đó *)? Bởi vì điều đó hoàn toàn khác với những gì được gọi là dự phòng, do đó làm cho câu hỏi của bạn trở nên hơi sai lệch.
Sergiy Kolodyazhnyy

Câu trả lời:


8

Bạn không thể. Cách để casevượt qua là thay thế ;;dải phân cách bằng ;&(hoặc ;;&). Và đó là một lỗi cú pháp để đặt nó bên trong nếu.

Bạn có thể viết toàn bộ logic ra như một điều kiện thông thường:

if [ "$input" != "foo" ] || [ "$VAR" = 1 ]; then
    one branch ...
else   # $input = "foo" && $VAR != 1
    another branch...
fi


@Isaac, tốt, vâng, mặc dù họ đã chỉ định dựa trên sự sụp đổ trên một if.
ilkkachu

+1 Để rõ ràng: Tôi đã bỏ phiếu cho câu trả lời của bạn. :).
NotAnUnixNazi

7

Tôi muốn đề xuất cơ cấu lại logic của bạn: thay vào đó hãy đặt mã "dự phòng" vào một hàm:

fallthrough() { echo 'fallthrough worked!'; }

for input in foo bar; do
    for var in 1 2; do
        echo "$input $var"
        case $input in
            foo)
                if (( var == 1 )); then
                    echo "falling through"
                    fallthrough
                else
                    echo "not falling through"
                fi
            ;;
            *) fallthrough;;
        esac
    done
done

đầu ra

foo 1
falling through
fallthrough worked!
foo 2
not falling through
bar 1
fallthrough worked!
bar 2
fallthrough worked!

7

Kịch bản sau đây biến bài kiểm tra của bạn "từ trong ra ngoài" theo nghĩa là chúng tôi kiểm tra $vartrước và sau đó thực hiện dự phòng (sử dụng ;&trong a case) tùy thuộc vào $input.

Chúng tôi làm điều này bởi vì câu hỏi về việc có "thực hiện dự phòng" hay không thực sự chỉ phụ thuộc vào $inputnếu $var1. Nếu đó là bất kỳ giá trị nào khác, câu hỏi về việc có nên thực hiện dự phòng hay không thậm chí không phải hỏi.

#/bin/bash

input='foo'
var='1'

case $var in
    1)
        case $input in
            foo)
                echo 'perform fallthrough'
                ;&
            *)
                echo 'fallthough worked'
        esac
        ;;
    *)
        echo 'what fallthrough?'
esac

Hoặc, không có case:

if [ "$var" -eq 1 ]; then
    if [ "$input" = 'foo' ]; then
        echo 'perform fallthrough'
    fi
    echo 'fallthough worked'
else
    echo 'what fallthrough?'
fi

Tôi nghĩ rằng bạn đã đóng đinh những gì OP thực sự muốn, dường như đang nhảy từ tuyên bố ban đầu của họ sang bất cứ điều gì trong *). Đã có +1 của tôi.
Sergiy Kolodyazhnyy

5

Không phải điều gì tôi sẽ làm, nhưng bạn có thể đạt được điều gì đó tiếp cận với:

shopt -s extglob # for !(*)
default='*'
case $input in
  (foo)
    if [ "$VAR" = 1 ]; then
      echo going for fallthrough
    else
      echo disabling fallthrough
      default='!(*)'
    fi ;;&

  ($default)
    echo fallthrough
esac

2

Kiểm tra cả hai biến cùng một lúc (bash 4.0-alpha +):

#!/bin/bash
while (($#>1)); do
    input=$1    VAR=$2
    echo "input=${input} VAR=${VAR}"; shift 2

    if [ "$VAR" = 1 ]; then new=1; else new=0; fi

    case $input$new in
    foo0)   echo "do not perform fallthrough"   ;;
    foo*)   echo "perform fallthrough"          ;&
    *)      echo "fallthrough worked!"          ;;
    esac

    echo
done

Về thử nghiệm:

$ ./script foo 0   foo 1   bar baz
input=foo VAR=0
do not perform fallthrough

input=foo VAR=1
perform fallthrough
fallthrough worked!

input=bar VAR=baz
fallthrough worked!

Sạch sẽ và đơn giản.

Hiểu rằng giá trị được kiểm tra ( $new) phải chỉ có hai giá trị có thể, đó là lý do tại sao mệnh đề if ở đó, để chuyển đổi VAR thành giá trị Boolean. Nếu VAR có thể được tạo thành Boolean, thì hãy kiểm tra 0(không 1) trong casevà loại bỏ if.


1

Bạn có thể đặt mặc định dự phòng nhưng đặt một điều kiện là mã chỉ thực thi nếu điều kiện được đáp ứng

#!/bin/bash

input='foo'
var='1'

case $input in
foo)
        echo "Do fall through"
;& #always fall through
*)
        if [ $var = "1" ] #execute only if condition matches
        then
        echo "fallthrough took place"
        fi
esac

Nhưng như ilkkachu đề xuất, bạn cũng có thể sử dụng các điều kiện thay vì chuyển đổi.


1

Nếu bạn không phiền ai đó phàn nàn về việc họ không hiểu mã của bạn, bạn chỉ cần chuyển thứ tự của hai điều kiện:

input="foo"
VAR="1"

if 
    case $input in
    foo)
        [ $VAR = "1" ]
    ;;
    esac
then
    echo "fallthrough worked!"
fi

Hoặc là:

input="foo"
VAR="1"

case $input in
foo)
    [ $VAR = "1" ]
;;
esac &&
    echo "fallthrough worked!"

Đơn giản và rõ ràng (ít nhất là với tôi). casekhông hỗ trợ dự phòng. Nhưng bạn có thể thay thế *)bằng &&sau esacđể làm cho nó tôn trọng các giá trị trả về của các nhánh khác.


-4

Mới ;&và các ;;&nhà khai thác đã được giới thiệu trong Bash 4.0 và mặc dù cả hai đều có thể hữu ích trong các tình huống tương tự tôi nghĩ rằng chúng không có ích trong trường hợp của bạn. Đây là những gì man bashnói về các nhà khai thác:

Nếu ;; Toán tử được sử dụng, không có kết quả khớp tiếp theo nào được thử sau khớp mẫu đầu tiên. Sử dụng; & thay cho ;; khiến việc thực thi tiếp tục với danh sách được liên kết với tập mẫu tiếp theo. Sử dụng ;; & thay cho ;; khiến shell kiểm tra danh sách mẫu tiếp theo trong câu lệnh, nếu có, và thực hiện bất kỳ danh sách liên quan nào trên một kết quả khớp thành công.

Nói cách khác, ;&là một sự sụp đổ và như chúng ta biết từ đó C;;&thực hiện bashkiểm tra các trường hợp còn lại thay vì casehoàn toàn trở về từ khối. Bạn có thể tìm thấy một ví dụ hay về ;;&hành động tại đây: /programming//a/24544780/3691891 .

Điều đó đang được nói, không phải ;&cũng không ;;&thể được sử dụng trong kịch bản của bạn bởi vì cả hai sẽ đi đến *)đó sẽ luôn luôn chạy.

Kịch bản sau đây hoạt động và thực hiện những gì bạn muốn mà không cần sắp xếp lại logic mà chỉ xem nó như một ví dụ và không bao giờ dựa vào nó, nó quá mong manh. Tôi đã lấy ý tưởng từ đây :

#!/usr/bin/env bash

function jumpto
{
    label=$1
    cmd=$(sed -n "/$label:/{:a;n;p;ba};" "$0" | grep -v ':$')
    cmd=$(echo "$cmd" | sed 's,;;,,')
    cmd=$(echo "$cmd" | sed 's,esac,,')
    eval "$cmd"
}

input="foo"
VAR="1"

case $input in
foo)
    if [ $VAR = "1" ]; then

        printf "perform fallthrough\n"
        jumpto ft
    else
        printf "do not perform fallthrough\n"

    fi
;;
*)
    ft:
    echo "fallthrough worked!"
;;
esac

Tại sao một downvote?
Arkadiusz Drabchot

1
Điều này có thể hoạt động trong một ví dụ đồ chơi nhưng nó gần như không thể hiểu được và sẽ không hoạt động trong một kịch bản lớn hơn. Cách bạn mô phỏng goto cực kỳ mong manh, và để nói rằng nó thực sự mô phỏng goto là một sự cường điệu. Mã trả về từ jumptohàm và thực thi bất cứ điều gì đến sau nó. Thực tế là điều này tương đương với việc tiếp tục thực thi sau khối giữa ft:;;là một sự trùng hợp ngẫu nhiên vì jumptolà lệnh cuối cùng trong cùng một lệnh phức tạp như khối nhảy lên.
Gilles 'SO- ngừng trở nên xấu xa'

1
OK, tôi nhấn mạnh rõ ràng rằng trong câu trả lời của tôi.
Arkadiusz Drabchot
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.