Lặp lại để thực hiện nhiều lệnh trong bash, bắt đầu từ đầu nếu một lệnh không thành công


0

Tôi đang xem xét một cách hiệu quả để làm điều này.

Tôi có nhiều lệnh khác nhau mà tôi cần phải thực hiện theo trình tự; cái thứ hai không thể chạy nếu cái thứ nhất thất bại và cứ thế.

Tôi đã lặp qua chúng; nhưng vòng lặp phải đi qua từng lệnh, đó không phải là điều tôi cần làm.

Chẳng hạn, nếu có 3 lệnh: a, b và c; a chạy mọi lúc, b chỉ chạy nếu a chạy thành công và c chỉ chạy nếu b chạy thành công, nhưng nếu b thất bại một lần, nó phải bắt đầu lại từ a

LOOP *****************************
until a; do
  echo "a failed, retrying"
  sleep(3)
done
until b; do
  echo "b failed, need to start all over"
  b_failed=1
  break
  START FROM THE BEGIN OF LOOP ***************
done
until c; do
  echo "c failed, need to start all over from a"
  c_failed=1
  break
  START FROM THE BEGIN OF LOOP ***************
done
.... OTHER INSTRUCTIONS
LOOP *****************************

Tôi đã cố gắng sử dụng một vòng lặp thông thường, nhưng giờ nghỉ sẽ thoát khỏi vòng lặp phụ và sẽ không bắt đầu lại từ đầu. Tôi muốn vào vòng lặp chính này, thực hiện thao tác đầu tiên cho đến khi nó vượt qua, sau đó thực hiện lần thứ hai; nếu thất bại, nó bắt đầu từ đầu vòng lặp, mà không chạy tất cả các lệnh khác, v.v. Mặc dù tôi dường như không thể tìm ra cách chính xác để làm như vậy, trừ khi tôi làm hỏng logic bằng một tấn if-if kiểm tra mọi lệnh.

Có một cách sạch sẽ để làm như vậy, trong vài dòng?

EDIT: đã viết trong khi thay vì cho đến khi; đã sửa

EDIT2: Cảm ơn rất nhiều cho giải pháp! Mặc dù nó phải được sửa đổi, vì tôi không thể chạy nó như hiện tại: if bị thiếu fi để chấm dứt lệnh và thiếu câu lệnh "then". Tôi đã không thể chạy việc bên trong nếu; Vì vậy, đây là những gì đang làm việc cho tôi:

while true; do
    until a; do
        echo "a failed, retrying"
        sleep(3)
    done
    if [ ! b ]; then
        echo "b failed, need to start all over"
        continue
    else
        c
    fi
    if [ ! c ]; then
        echo "c failed, need to start all over from a"
        continue
    else
        break
    fi
done

Tôi nghĩ bạn có thể bối rối về những gì while làm. while là một vòng lặp và hiện tại phần đầu tiên của bạn sẽ tiếp tục lặp lại "một thất bại, thử lại" cứ sau 3 giây miễn là a là thành công. Nó sẽ chỉ chuyển sang b khi nào a thất bại
8bittree

Vài điều như 8bittree đã đề cập ở trên: 1. bạn phải kiểm tra xem a, b hoặc c có bị lỗi trong các câu lệnh while hay không. 2. đặt toàn bộ mã của bạn vào một mệnh đề while khác để kiểm tra một biến tùy chỉnh cho biết liệu mọi thứ có thực thi khi cần trong quá trình thực thi các lệnh của bạn hay không. Nếu không, đặt nó phù hợp trong nội bộ các câu lệnh while và kiểm tra giá trị của nó giữa các câu lệnh while. Nếu giá trị chỉ ra rằng có một vấn đề trong lệnh trên, hãy tạo một continue dòng để bắt đầu lại từ đầu.
Mike

3
a & amp; & amp; b & amp; & amp; c; sẽ chỉ thực hiện b và c nếu lệnh trước chạy thành công.
Squeezy

Khi a, b và c hoàn thành thành công, bạn có muốn chạy lại tất cả chúng trong một vòng lặp không, hay bạn chỉ đang cố gắng đảm bảo rằng tất cả chúng đều chạy một lần, theo thứ tự, không có lỗi ở giữa?
8bittree

Xin lỗi, đã viết nó một cách nhanh chóng và thay vì cho đến khi tôi viết trong khi. Tôi đã cố gắng đơn giản hóa trường hợp. Về cơ bản tôi cần một cách để thực hiện vòng lặp chính (phần LOOP) và cách thoát khỏi các vòng lặp phụ bắt đầu từ đầu
rataplan

Câu trả lời:


3

Một giải pháp rất đơn giản, như được đề cập một phần bởi Squeezy:

until a && b && c; do
    :
done

&& là logic và toán tử. Nó ngắn mạch, do đó biểu thức bên phải chỉ được đánh giá khi biểu thức bên trái là đúng.

Giá trị trả về của hoàn thành && biểu thức (hoặc chuỗi của && s) là kết quả của biểu thức được đánh giá cuối cùng. Vì vậy, nếu bất kỳ một trong ba lệnh ở đây không thành công, các lệnh sau sẽ bị bỏ qua và until sẽ thấy một false và nhập vào cơ thể của nó, không làm gì cả ( : chỉ là no-op để điền vào phần thân của vòng lặp) và lặp lại điều kiện kiểm tra a && b && c lần nữa. Nếu cả ba thành công, thì until sẽ thấy một true Và kết thúc.

Vì vậy, điều này tốt cho trường hợp đơn giản, nhưng không tốt nếu bạn muốn in những thông điệp trạng thái đó. Điều đó là có thể với || (logic hoặc) và { }, nhưng nó sẽ rất lộn xộn.

Điều này tốt hơn nếu bạn muốn làm gì đó thêm khi lệnh thất bại, chẳng hạn như thông báo trạng thái echo:

while true; do
    until a; do
        echo "a failed, retrying"
        sleep(3)
    done
    if [ ! `b` ]; then
        echo "b failed, need to start all over"
        continue
    fi
    if [ ! `c` ]; then
        echo "c failed, need to start all over from a"
        continue
    fi
    break
done

continue trở về điểm bắt đầu của vòng lặp kèm theo. Đặt một số sau khi nó trở về điểm bắt đầu của vòng lặp kèm theo n lên cấp. Mặc dù điều đó không cần thiết ở đây, bởi vì chúng ở bên trong if s thay vì vòng lặp. Ngẫu nhiên, break tương tự sẽ lấy một số và thoát ra khỏi n vòng lặp kèm theo.

Các a phần cũng có thể là một if [ ! a ]; thay cho until vòng lặp, nếu bạn muốn giữ mọi thứ trông giống nhau. Bạn cần thêm một continue trong trường hợp đó.


Cảm ơn rất nhiều! Tôi chưa bao giờ phải đối mặt với logic như vậy; Vì vậy, thật thú vị khi tìm hiểu làm thế nào nó thực sự hoạt động. Ngày xưa bạn sẽ sử dụng goto và nhãn, nhưng đó là một cách quái quỷ để làm mọi việc. Vì vậy, nếu tôi ghép các lệnh, nếu vượt qua và b thất bại, nó sẽ bắt đầu lại từ đầu? Bởi vì nếu không thì nó sẽ không làm việc cho tôi. Tôi đang thử cách tiếp cận thứ hai, dài hơn nhưng có vẻ phù hợp với trường hợp của tôi.
rataplan

2
@newbiez: giải pháp thứ hai đại khái là những gì tôi muốn bạn làm. Giải pháp đơn giản đầu tiên là giải pháp bash-y xương trần sẽ bắt đầu đánh giá từ đầu (từ trái sang phải). giải pháp thứ hai là cách tổng quát hơn để thực hiện nó trong tập lệnh bash khi bạn cần làm gì đó nếu một lệnh cụ thể không thành công.
Mike

1
@newbiez Tôi đã thêm một số giải thích về những gì đang xảy ra với giải pháp đầu tiên. Tôi cũng nhận ra rằng, kể từ khi bc đang xảy ra bên trong if s thay vì vòng lặp, continue Không cần thêm số, và trên thực tế có thể có hại nếu toàn bộ điều này nằm trong một vòng lặp khác.
8bittree

1
Nhiều đánh giá cao. BTW tôi có cần nghỉ ngơi ở cuối, sau câu lệnh if cuối cùng để thoát khỏi vòng lặp while không? Vì nó chỉ là "sự thật"; nó sẽ tiếp tục mãi mãi, phải không?
rataplan

@newbiez Đúng, và tôi đã sửa nó. Bạn cũng có thể sử dụng một done=false; until $done và thiết lập done=true vào cuối nếu bạn thích
8bittree
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.