Sử dụng $? trong một câu lệnh if


12
function foo {
   (cd $FOOBAR;
   <some command>
   if [$? -ne 0]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

Tôi đang cố gắng viết một hàm giống như ở trên và đặt nó vào tệp .bashrc của tôi. Sau khi tôi lấy tệp và chạy, tôi nhận được:

Tổng thời gian: 51 giây
-bash: [1: lệnh không tìm thấy
OK!

Ai đó có thể giúp tôi hiểu những gì tôi đã làm sai?


4
Kiểm tra nếu $?bằng 0 với một ifcâu lệnh là vô nghĩa, ifmong đợi một lệnh và nếu lệnh được trả về 0, nó sẽ chạy mã trong khối. vì vậy if true; then echo hello; fisẽ vang xin chào kể từ khi lệnh truetrở lại 0.
llua

1
@llua Nó không vô nghĩa. $?giữ trạng thái của đường ống cuối cùng , không phải là lệnh test( [) trong ifcâu lệnh. Ví dụ là kiểm tra xem some commandđã thành công. Bạn có thể làm tương tự với &&||, nhưng nó có thể tạo ra các dòng dài, không thể đọc được so với if [ $? -eq 0 ]. Lập luận tương tự cũng xảy raif some command
bonsaiviking 5/214

@bottoviking Tôi nhận thức rõ về những gì $?mở rộng ra, tôi chỉ ra rằng không có điểm nào trong việc testsử dụng; kể từ khi if some commandlàm điều tương tự với một câu lệnh so với việc có hai câu lệnh riêng biệt. nếu lệnh đã dài, việc thêm ba ký tự sẽ không làm cho 'không thể đọc được' khủng khiếp hơn 'không thể đọc được'.
llua

Câu trả lời:


33

Thêm một khoảng trắng sau [và một khoảng trắng trước ]:

function foo {
   (cd $FOOBAR;
   <some command>
   if [ $? -ne 0 ]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

[là một dựng sẵn vỏ, nó là một lệnh giống như echo, read, expr... nó cần một không gian sau nó, và đòi hỏi một khớp ].

Viết [ $? -ne 0 ]thực sự là cách gọi [và cho nó 4 thông số: $?, -ne, 0, và ].

Lưu ý: thực tế là bạn đang nhận được thông báo lỗi [1: command not foundcó nghĩa $?là có giá trị 1.


1
Tôi vừa xác minh rằng câu trả lời của bạn là chính xác trên máy ảo Linux của tôi.
samiam

[là một liên kết đến testcũng
Ricky chùm

2
@RickyBeam trong hầu hết các shell, [là một shellin và /usr/bin/[hiếm khi được sử dụng.
Patrick

20

Hoặc bạn có thể bỏ qua $?hoàn toàn. Nếu lệnh của bạn là cmd, sau đây sẽ hoạt động:

function foo {
   (cd $FOOBAR;
   if cmd
   then
      echo "OK!"
   else
      echo "Nope!"
   fi
   )
}

6

Đó là một cách thực hành tốt để gán giá trị trả về cho một biến trước khi sử dụng nó

retval="$?"
if [ $retval -ne 0 ]

Nó cho phép bạn sử dụng lại giá trị trả về. ví dụ: trong một tuyên bố nếu ... elif ... khác ....


-1: Bạn đã quên khoảng trắng sau [(Không có khoảng trắng, nó sẽ trở thành lỗi cú pháp bash) Sẽ hoàn tác nếu bạn chỉnh sửa và sửa lỗi.
samiam

Đúng, bạn đúng. Tôi sửa nó rồi.
Abdul

@samiam rằng bình luận cuối cùng đã nhắm vào bạn
terdon

4
:) Bạn có thể mở rộng câu trả lời của bạn một chút. Tại sao nó là thực hành tốt? Những loại lỗi có thể tránh được?
terdon

1
@terdon Thực tế không tốt khi sử dụng $?trực tiếp vì điều đó sẽ bị hỏng nếu bạn từng chỉnh sửa tập lệnh sau đó, đặt một dòng giữa lệnh và $?kiểm tra.
samiam

3

Lý do duy nhất khiến bạn muốn sử dụng $?làm đối số cho [lệnh (cho dù [lệnh đó có được chạy trong phần điều kiện của ifcâu lệnh hay không) là khi bạn muốn phân biệt đối xử về trạng thái trả về cụ thể, như:

until
  cmd
  [ "$?" -gt 1 ]
do
  something
done

Cú pháp cho tất cả những if, while, until... báo cáo là

if cmd-list1
then cmd-list2
else cmd-list3
fi

Mà chạy cmd-list2nếu cmd-list1thành công hoặc cmd-list3cách khác.

Các [ "$?" -eq 0 ]lệnh là một không-op. Nó đặt $?thành 0 nếu $?là 0 và $?khác không nếu nó khác không.

Nếu bạn muốn chạy một cái gì đó nếu cmdthất bại, đó là:

if ! cmd
then ...
fi

Nói chung, bạn không cần phải tự mày mò $?để biết giá trị nào có nghĩa là truehay false. Các trường hợp duy nhất như tôi đã nói ở trên nếu bạn cần phân biệt đối xử trên một giá trị cụ thể hoặc nếu bạn cần lưu nó sau này (ví dụ để trả về nó dưới dạng giá trị trả về của hàm) như:

f() {
  cmd; ret=$?
  some cleanup
  return "$ret"
}

Cũng cần nhớ rằng để lại một biến không được trích dẫn là toán tử split + global. Sẽ không có ý nghĩa khi gọi toán tử đó ở đây, vì vậy nó phải là:

[ "$?" -ne 0 ]

không [ $? -ne 0 ], hãy để một mình [$? -ne 0 ](mà sẽ chỉ gọi [lệnh nếu $IFStình cờ có chứa ký tự đầu tiên của $?).

Cũng lưu ý rằng cách Bourne để xác định hàm là dán function-name()trước lệnh. Đó là trường hợp trong mọi Bourne như shell ngoại trừ bashyash(và các phiên bản gần đây của posh) chỉ cho phép một lệnh ghép (các lệnh ghép là {...}hoặc (...)hoặc những thứ như for...done, if...fi...

function foo { ... }kshcú pháp định nghĩa hàm. Không có lý do tại sao bạn muốn sử dụng nó ở đây.

Mã của bạn có thể được viết (POSIXly) bằng văn bản:

foo() (
  cd -P -- "$FOOBAR" || return # what if the cd failed!
  if
    <some command>
  then
    echo 'OK!'
  else
    echo 'Nope!'
  fi
)

Cũng lưu ý rằng cdkhông -Pcó ý nghĩa rất đặc biệt (xử lý các đường dẫn có chứa ..các thành phần khác với bất kỳ lệnh nào khác), vì vậy tốt hơn là đưa nó vào tập lệnh để tránh nhầm lẫn.

(hàm đó trả về falsenếu cdthất bại, nhưng không phải nếu <some command>thất bại).


1

Tôi tin rằng lệnh dưới đây sẽ làm mọi thứ bạn muốn trong một dòng.

(( verify = $?!=0?'Nope!':'OK!' ))
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.