Bash bỏ qua lỗi cho một lệnh cụ thể


444

Tôi đang sử dụng các tùy chọn sau

set -o pipefail
set -e

Trong bash script để dừng thực thi khi có lỗi. Tôi có ~ 100 dòng thực thi tập lệnh và tôi không muốn kiểm tra mã trả về của mỗi dòng trong tập lệnh.

Nhưng đối với một lệnh cụ thể, tôi muốn bỏ qua lỗi. Làm thế nào tôi có thể làm điều đó?

Câu trả lời:


757

Giải pháp:

particular_script || true

Thí dụ:

$ cat /tmp/1.sh
particular_script()
{
    false
}

set -e

echo one
particular_script || true
echo two
particular_script
echo three

$ bash /tmp/1.sh
one
two

three sẽ không bao giờ được in

Ngoài ra, tôi muốn thêm rằng khi pipefailbật, nó đủ để shell nghĩ rằng toàn bộ đường ống có mã thoát khác không khi một trong các lệnh trong ống có mã thoát khác không ( pipefailphải tắt mã cuối cùng) .

$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0

15
+1. Như Hướng dẫn tham khảo Bash giải thích , "Shell không thoát" khi -ethuộc tính được đặt "nếu lệnh bị lỗi là một phần của danh sách lệnh ngay sau một whilehoặc untiltừ khóa, một phần của kiểm tra trong một ifcâu lệnh, một phần của bất kỳ lệnh nào được thực thi trong một &&hoặc ||danh sách ngoại trừ lệnh theo sau lệnh cuối cùng &&hoặc ||bất kỳ lệnh nào trong đường ống ngoại trừ lệnh cuối cùng hoặc nếu trạng thái trả về của lệnh đang được đảo ngược !. "
ruakh

@IgorChubin Tôi không biết tại sao nhưng điều này không hoạt động đầu ra = (ldd $2/bin/* || true) | grep "not found" | wc -lscript bị chấm dứt sau dòng này khi thất bại trở lại
Vivek Goel

1
(ldd $2/bin/* || true) | grep "not found" | wc -l || true
Igor Chubin

1
set -o pipefail. khi grepkhông tìm thấy gì, nó trả về mã thoát khác không và đủ để shell nghĩ rằng toàn bộ đường ống có mã thoát khác không.
Igor Chubin

3
Nếu bạn muốn tùy chọn duy trì giá trị trả về (không thoát), bạn hãy thử mycommand && true. Điều này cho phép bạn kiểm tra mã trả về trong các bước tiếp theo và xử lý nó theo chương trình.
Ed Ost

178

Chỉ cần thêm || truesau lệnh mà bạn muốn bỏ qua lỗi.


11
Tôi nghĩ điều quan trọng là thêm điều này: phương pháp này sẽ cho phép mã phản hồi và thông báo lỗi tồn tại, trong khi "!" phương pháp được nêu dưới đây sẽ thay đổi mã phản hồi và do đó không tạo ra lỗi. Đây là điều quan trọng khi sử dụng set -evà cố gắng để nắm bắt một thông báo lỗi: ví dụset -e; TEST=$(foo 2>&1 || true); echo $TEST
Spanky

87

Đừng dừng lại và cũng lưu trạng thái thoát

Chỉ trong trường hợp nếu bạn muốn tập lệnh của mình không dừng nếu một lệnh cụ thể không thành công và bạn cũng muốn lưu mã lỗi của lệnh không thành công:

set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE

2
Đây chính xác là những gì tôi cần
sarink

không làm việc cho tôi vì một số lý do ... oh tốt
Jeef

EXIT_CODE không được đặt thành 0 khi lệnh trả về 0. Mã thoát không bằng 0 được bắt mặc dù. Bất cứ ý tưởng tại sao?
Ankita13

@ Ankita13 Bởi vì nếu nó bằng 0 thì lần đầu tiên commandđã thành công và cần phải chạy những gì sau đó ||. đọc nó như: nếu commandthất bại, làm EXIT_CODE=$?. Bạn có thể chỉ cần làm command || echo "$?"hoặc sử dụng "bẫy" để gỡ lỗi dài dòng hơn. Xem cái này -> stackoverflow.com/a/6110446/10737630
tinnick

63

Chính xác hơn:

! particular_script

Từ đặc tả POSIX liên quan đến set -e(nhấn mạnh của tôi):

Khi tùy chọn này được bật, nếu một lệnh đơn giản không thành công vì bất kỳ lý do nào được liệt kê trong Hậu quả của lỗi Shell hoặc trả về giá trị trạng thái thoát> 0 và không phải là một phần của danh sách ghép sau một thời gian, cho đến khi, hoặc nếu từ khóa, và không phải là một phần của danh sách AND hoặc OR và không phải là một đường ống dẫn trước! từ dành riêng , sau đó vỏ sẽ thoát ngay lập tức.


16
Điều này chỉ đảo ngược mã thoát của một lệnh, vì vậy lệnh đã hoàn thành thành công sẽ trả về 1 thay vì 0 và thất bại với tập lệnh -e.
Marboni

17
Sự hiểu biết của tôi là ý !chí ngăn chặn vỏ thoát ra bất kể điều gì. Kịch bản này hiển thị thông báo Still alive!khi tôi chạy nó, cho biết rằng kịch bản đã chạy đến khi hoàn thành. Bạn đang thấy hành vi khác nhau?
Lily Finley

7
bạn đã đúng, nó đảo ngược trạng thái thoát, nhưng không gặp sự cố khi lệnh kết thúc bằng cả 0 hoặc 1. Tôi đã không chú ý. Dù sao, cảm ơn bạn đã trích dẫn tài liệu, tôi đặt biểu thức của tôi để ifmệnh đề và giải quyết vấn đề.
Marboni

42

Thay vì "trả về true", bạn cũng có thể sử dụng tiện ích "noop" hoặc null (như được đề cập trong thông số kỹ thuật POSIX ) :và chỉ "không làm gì cả". Bạn sẽ lưu một vài chữ cái. :)

#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."

3
mặc dù | |: không rõ ràng như | | đúng (có thể gây nhầm lẫn cho người dùng không phải là chuyên gia), tôi thích sự đồng nhất
David

Biến thể này không trả về bất kỳ văn bản nào có thể quan trọng trong CI.
kivagant

5

Nếu bạn muốn ngăn chặn tập lệnh của mình thất bại thu thập mã trả về:

command () {
    return 1  # or 0 for success
}

set -e

command && returncode=$? || returncode=$?
echo $returncode

returncode được thu thập bất kể lệnh thành công hay thất bại.


2

Tôi đã sử dụng đoạn mã dưới đây khi làm việc với các công cụ CLI và tôi muốn biết liệu một số tài nguyên có tồn tại hay không, nhưng tôi không quan tâm đến đầu ra.

if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
    echo "none exist actually exist!"
fi

1
Đây dường như là một đường vòng thực sự và cách nói vừa phải đắt tiềnif [ -r not_exist ]
tripleee

1

Tôi thích giải pháp này:

: `particular_script`

Lệnh / script giữa các tick phía sau được thực thi và đầu ra của nó được đưa vào lệnh ":" (tương đương với "true")

$ false
$ echo $?
1
$ : `false`
$ echo $?
0

chỉnh sửa: Sửa lỗi chính tả xấu


0

trong khi || trueđược ưu tiên, nhưng bạn cũng có thể làm

var=$(echo $(exit 1)) # it shouldn't fail

0

Không có giải pháp nào hiệu quả với tôi từ đây, vì vậy tôi đã tìm thấy một giải pháp khác:

set +e
find "./csharp/Platform.$REPOSITORY_NAME/obj" -type f -iname "*.cs" -delete
find "./csharp/Platform.$REPOSITORY_NAME.Tests/obj" -type f -iname "*.cs" -delete
set -e

Điều này rất hữu ích cho CI & CD. Bằng cách này, các thông báo lỗi được in nhưng toàn bộ tập lệnh tiếp tục thực thi.


0
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
echo $output
echo $exit_status

Ví dụ về việc sử dụng điều này để tạo một tệp nhật ký

log_event(){
timestamp=$(date '+%D %T') #mm/dd/yy HH:MM:SS
echo -e "($timestamp) $event" >> "$log_file"
}

output=$(*command* 2>&1) && exit_status=$? || exit_status=$?

if [ "$exit_status" = 0 ]
    then
        event="$output"
        log_event
    else
        event="ERROR $output"
        log_event
fi

0

Cảm ơn giải pháp đơn giản ở đây từ phía trên:

<particular_script/command> || true

Cấu trúc sau đây có thể được sử dụng cho các hành động / xử lý sự cố bổ sung của các bước tập lệnh và các tùy chọn kiểm soát luồng bổ sung:

if <particular_script/command>
then
   echo "<particular_script/command> is fine!"
else
   echo "<particular_script/command> failed!"
   #exit 1
fi

Chúng tôi có thể phanh các hành động tiếp theo và exit 1nếu cầ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.