Cách giữ trạng thái thoát cuối cùng sau khi kiểm tra


8

Có thể giữ trạng thái thoát lệnh cuối cùng ( $?) không bị thay đổi sau khi kiểm tra không?

Ví dụ, tôi muốn làm:

command -p sudo ...
[ $? -ne 1 ] && exit $?

Cái cuối cùng exit $?sẽ trả về trạng thái thoát sudo, nhưng thay vào đó nó luôn trả về 0(mã thoát của kiểm tra).

Có thể làm điều đó mà không có một biến tạm thời?

Một ví dụ khác để làm rõ hơn:

 spd-say "$@"
 [ $? -ne 127 ] && exit $?

Trong trường hợp này tôi chỉ muốn thoát nếu lệnh đầu tiên được tìm thấy (mã thoát! = 127). Và tôi muốn thoát với spd-saymã thoát thực tế (nó có thể không 0).

EDIT: Tôi quên đề cập rằng tôi thích giải pháp khiếu nại POSIX để có tính di động tốt hơn.

Tôi sử dụng cấu trúc này trong các tập lệnh mà tôi muốn cung cấp các lựa chọn thay thế cho cùng một lệnh. Ví dụ, xem tập lệnh crc32 của tôi .

Vấn đề với các biến tạm thời là chúng có thể che khuất các biến khác và để tránh việc bạn phải sử dụng tên dài, điều này không tốt cho khả năng đọc mã.


Không, nhưng bạn chỉ có thể làm điều if ! command -p sudo; then exit; fiđó sẽ có kết quả tương tự cho ví dụ của bạn.
jordanm

ok, nếu tôi muốn kiểm tra mã 127 thì sao? (ví dụ. [ $? -ne 127 ] && exit $?)
eadmaster

1
@jordanm: Thật sao? Nếu OP đã trình bày mã / logic mà anh ta muốn nói và nếu tôi đọc chính xác, anh ta muốn thoát tập lệnh nếu sudolệnh thành công (nghĩa là, nếu sudothoát với trạng thái 0). Nhưng, trong mã của bạn, tập lệnh sẽ tiếp tục chạy (không thoát) nếu sudothành công
G-Man nói 'Phục hồi Monica'

@ G-Man - Tôi khá chắc chắn rằng các điều kiện của người hỏi thực sự dựa trên sự trở lại commandvà hoàn toàn không sudo. Đó là ý nghĩa của việc tôi muốn thoát chỉ khi tìm thấy lệnh đầu tiên (mã thoát! = 127) và là một trả về được chỉ địnhcommand khi không tìm thấy lệnh mà nó gọi. Tôi đoán vấn đề là việc gọi sudonhư là một phần của bài kiểm tra cho phép sudoxóa bỏ sự trở lại của commandvị trí đầu tiên và do đó làm sai lệch bài kiểm tra.
mikeerv

Câu trả lời:


3

$_sẽ làm việc trong (ít nhất) tương tác dash, bash, zsh, ksh (mặc dù rõ ràng là không trong một tuyên bố có điều kiện theo yêu cầu)mkshvỏ. Trong số đó - theo hiểu biết của tôi - chỉ bashzshcũng sẽ đưa nó vào một lớp vỏ theo kịch bản. Nó không phải là một tham số POSIX - nhưng khá dễ mang theo bất kỳ vỏ tương tác hiện đại nào.

Đối với một giải pháp di động hơn, bạn có thể làm:

command -p sudo ...
eval '[ "$?" = 127 ] || exit '"$?"

Về cơ bản cho phép bạn mở rộng giá trị ban đầu cho $?phần đuôi của tập lệnh trước khi thậm chí kiểm tra giá trị của nó ở phần đầu của tập lệnh.

Nhưng dù sao đi nữa, vì bạn dường như đang kiểm tra xem lệnh sudocó thể được tìm thấy trong chuỗi -p đường dẫn di động dựng sẵn của shell hay không command, tôi nghĩ bạn có thể truy cập trực tiếp vào nó. Ngoài ra, chỉ để được rõ ràng, command sẽ không kiểm tra vị trí của bất kỳ đối số để sudo- vì vậy nó chỉ là sudo- và không có gì nó gọi - đó là có liên quan với giá trị trả về.

Và dù sao đi nữa, nếu đó là những gì bạn đang cố gắng làm:

command -pv sudo >/dev/null || handle_it
command -p  sudo something or another

... sẽ hoạt động tốt như một bài kiểm tra mà không có bất kỳ lỗi nào trong lệnh sudochạy trở lại theo cách có thể làm sai lệch kết quả kiểm tra của bạn.


9

Có nhiều tùy chọn khác nhau để xử lý trạng thái thoát đáng tin cậy mà không cần chi phí, tùy thuộc vào yêu cầu thực tế.

Bạn có thể lưu trạng thái thoát bằng một biến:

command -p sudo ...
rc=$?
[ "$rc" -ne 1 ] && echo "$rc"

Bạn có thể trực tiếp kiểm tra thành công hay thất bại:

if  command -p sudo ...
then  echo success
else  echo failure
fi

Hoặc sử dụng casecấu trúc để phân biệt trạng thái thoát:

command -p sudo ...
case $? in
(1) ... ;;
(127) ... ;;
(*) echo $? ;;
esac

với trường hợp đặc biệt được hỏi trong câu hỏi:

command -p sudo ...
case $? in (1) :;; (*) echo $?;; esac

Tất cả các tùy chọn đó có lợi thế là chúng phù hợp với tiêu chuẩn POSIX.

(Lưu ý: Để minh họa, tôi đã sử dụng echocác lệnh ở trên; thay thế bằng các exitcâu lệnh thích hợp để khớp với chức năng được yêu cầu.)


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
terdon

1
(Tôi tự hỏi tại sao bình luận cuối cùng không chuyển sang trò chuyện.) - Như đã được giải thích rõ ràng và được hỗ trợ bởi các trích dẫn POSIX trong cuộc thảo luận trò chuyện (xem tại đó để biết chi tiết); 1.) ("$(get_errnos)")là một bổ sung nhân tạo của một sự thay thế lệnh trong đó so sánh với các mã lỗi thực tế được yêu cầu trong câu hỏi, 2.) Có tiêu chuẩn rõ ràng về những thay đổi $?(và do đó những gì không thay đổi nó) và 3.) ở đó không có tác dụng phụ với cấu trúc đó (trừ khi, như bạn đã làm, bạn giới thiệu chúng một cách không cần thiết). - OTOH, vì bạn thấy phiền, câu trả lời khác mà bạn thích rõ ràng là không chuẩn.
Janis

1
@mikeerv; Thật khó chịu (và gây hiểu lầm!) Không chỉ bởi vì bạn áp dụng tiêu chuẩn kép ! Nếu bạn áp dụng cùng một $(get_errnos)mã nhân tạo cho bất kỳ giải pháp nào khác ( ( exit 42 ); test "$(get_errnos)" -ne $? && echo $_) thì chúng cũng không hoạt động. (Bạn muốn mang giải pháp tiêu chuẩn của tôi trong miscredit, chứ không phải các hack không chuẩn khác .) - Tất nhiên bạn có thể thêm mã tùy ý vào bất kỳ câu trả lời nào và làm hỏng nó. - Và WRT để thay đổi $?; chỉ vì bạn không thể tìm thấy nó không có nghĩa là nó không đúng. (Tôi đã cung cấp trong các cuộc thảo luận của chúng tôi ngay cả các từ khóa để tìm kiếm trong POSIX.)
Janis

1
@mikeerv; Nhưng điều này, một lần nữa, có xu hướng tiếp tục cuộc thảo luận (không có kết quả và vô tận), không nên đặt ở đây vì @terdon quan sát chính xác.
Janis

1
@mikeerv; Tôi đã nói khá rõ ngay từ đầu khi bạn đề cập lần đầu zsh(lần đầu tiên được đề cập; sau này bạn cũng đã thêm dash) rằng tôi nghĩ đó phải là một lỗi ở đó, với điều kiện là casetrạng thái thoát và cài đặt $?có vẻ được xác định rõ trong POSIX. - Và cũng ở đây, một lần nữa, bạn áp dụng tiêu chuẩn kép; bản hack khác, ví dụ, không phải là tiêu chuẩn, cũng không hoạt động đáng tin cậy trong các shell tiêu chuẩn khác (ví dụ: không có trong ksh). - Các đề xuất của tôi là tiêu chuẩn và hoạt động bash(chủ yếu được sử dụng trên Linux) và ksh(vỏ chiếm ưu thế trong các Unix thương mại).
Janis

7
command -p ...
test 1 -ne $? && exit $_

Sử dụng $_, mở rộng đến đối số cuối cùng của lệnh trước đó.


1
Hợp lệ cho ví dụ cụ thể này, nhưng chỉ có thể sử dụng được nếu không có lệnh nào khác ở giữa $?và các $_tham chiếu. IMHO tốt hơn là nên tuân thủ một phương pháp nhất quán, hoạt động trong các trường hợp khác (và cũng có thể giúp với khả năng đọc mã).
Dan Cornilescu

4
Shell được đặt tên cụ thể hai lần, một lần trong tiêu đề và một lần dưới dạng thẻ. Tính di động cũng không được đề cập ở bất cứ đâu trong câu hỏi, vì vậy tôi đã đưa ra một câu trả lời hoạt động trong phần vỏ nói trên. Những hạn chế kỳ lạ khác sẽ được tạo thành?
llua

1
@mikeerv; Trong trường hợp bạn bỏ lỡ nó: Tôi đã nói: "Có một bình luận đầu tiên ở đây về POSIX." mà đã được sửa chữa. Không nhiều không ít. - Như đã tranh luận kỹ lưỡng với bạn và giải thích ở đó, cả ba gợi ý trong câu trả lời khác đều được POSIX xác định rõ. Không cần lặp lại ý kiến ​​(IMO sai) của bạn ở đây, hoặc bắt đầu một bước lặp khác của tranh chấp.
Janis

1
@mikeerv; Các tác dụng phụ mở rộng trong các case mẫu , nơi duy nhất quan trọng trong lý thuyết (nhưng không phải trong câu hỏi đã cho), là một trường hợp được xây dựng. - Trong mọi trường hợp, thay thế lệnh shell của bạn sẽ truyền kết quả của lệnh nhúng, thông thường các mở rộng khác sẽ không ảnh hưởng đến trạng thái trả về nếu không có lệnh nào liên quan có thể tạo ra lỗi ( x=${a!b}trường hợp tâm trí , nhưng không liên quan ở đây). - Ý của bạn là "lệnh không có tên lệnh" là gì?
Janis

1
@mikeerv; Nó có thể bị ghi đè chỉ bởi ad hoc tạo thành mã không cần thiết. Hoàn toàn không có khu vực màu xám nếu bạn đưa ra gợi ý mà không cần thiết phải giới thiệu vô nghĩa nhân tạo. Các yêu cầu hoàn toàn rõ ràng trong trường hợp này: 1. thực hiện một comand, 2. kiểm tra mã thoát, 3. trả lại mã thoát. - Bạn nhận được chưa? - Bạn đã thay đổi yêu cầu đó một cách tùy tiện để chỉ tạo ra một đối số.
Janis

6

Bạn có thể định nghĩa (và sử dụng) hàm shell:

check_exit_status()
{
    [ "$1" -ne 1 ] && exit "$1"
}

Sau đó

command -p sudo ...
check_exit_status "$?"

Có thể cho rằng, đây là "gian lận", vì nó tạo một bản sao $?trong check_exit_statusdanh sách đối số.

Điều này có vẻ hơi khó xử, và nó là. (Điều đó đôi khi xảy ra khi bạn áp đặt các ràng buộc tùy ý cho các vấn đề.) Điều này có vẻ không linh hoạt, nhưng nó không phải là. Bạn có thể làm cho check_exit_statusphức tạp hơn, thêm các đối số cho nó biết (các) thử nghiệm nào sẽ thực hiện trên giá trị trạng thái thoát.


0

Để trả lời câu hỏi trực tiếp của bạn, không, không thể $?không thay đổi. Và đây là một trong những trường hợp tôi nghi ngờ bạn đang tập trung vào vấn đề sai. Một biến tạm thời là cách tiêu chuẩn và ưa thích để có được hiệu ứng mà bạn đang tìm kiếm. Đó là tiêu chuẩn đến mức tôi sẽ đề nghị từ bỏ (hoặc suy nghĩ lại) bất cứ lý do gì bạn nghĩ rằng bạn không muốn sử dụng nó; Tôi rất nghi ngờ rằng nó đáng giá thêm độ phức tạp được thêm vào bởi bất kỳ phương pháp nào khác.

Nếu bạn chỉ hỏi vì tò mò đơn giản, thì câu trả lời là không.


@mikeerv Tôi không chắc là tôi hiểu - bạn đang nói về việc gán thủ công $?hoặc một cái gì đó tương tự?
David Z

0

Đây là đoạn mã của tôi để giữ trạng thái thoát trước đó mà không thoát khỏi tập lệnh / shell hiện tại

EXIT_STATUS=1
if [[ $EXIT_STATUS == 0 ]]
then
  echo yes
else
  (exit $EXIT_STATUS)
fi
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.