Cách thực hành tốt nhất để biểu thị giá trị boolean trong tập lệnh shell là gì?


15

Tôi biết rằng có các giá trị boolean trong bash, nhưng tôi chưa bao giờ thấy chúng được sử dụng ở bất cứ đâu.

Tôi muốn viết một trình bao bọc cho một số thông tin thường được tra cứu trên máy của tôi, ví dụ, là ổ USB cụ thể này được lắp / gắn.

Điều gì sẽ là thực hành tốt nhất để đạt được điều đó?

  • Một chuỗi?

    drive_xyz_available=true
  • Một số (0 cho đúng, ≠ 0 cho sai)?

    drive_xyz_available=0    # evaluates to true
  • Một chức năng?

    drive_xyz_available() { 
        if available_magic; then 
                return 0 
        else 
                return 1 
        fi
    }
    

Tôi chủ yếu tự hỏi về những gì người khác muốn sử dụng trình bao bọc. Họ sẽ mong đợi một giá trị boolean, một lệnh như biến hoặc hàm để gọi?

Từ quan điểm bảo mật tôi sẽ nghĩ rằng tùy chọn thứ hai là an toàn nhất, nhưng tôi rất thích nghe những trải nghiệm của bạn.


3
help true ; help false ; help exit
Costas

3
@Costas Bạn có phiền khi xây dựng?
Minix

Câu trả lời:


2
bool(){ return "$((!${#1}))"; }

if bool "$var"
then : do true
else : do false

Chỉ cần đặt một biến thành bất cứ điều gì nhưng không-null để ở trên hoạt động, mặc dù [ -n "$var" ]sẽ ngắn hơn, nếu không rõ ràng.

Nói chung khi tập lệnh diễn giải một biến môi trường là đúng hoặc sai, nó sẽ diễn giải bất kỳ giá trị nào là đúng (và đôi khi sử dụng giá trị đã nói để định cấu hình một số tùy chọn) hoặc nếu không thì giá trị null là sai.

Ở trên trả về !notgiá trị boolean của len của đối số đầu tiên - nếu đối số chứa bất kỳ số ký tự nào khác 0, thì trả về 0, nếu không, không có ký tự nào [ -n "$var" ], về cơ bản, đây là cùng một bài kiểm tra mà bạn có thể thực hiện , nhưng nó chỉ gói nó trong một chức năng nhỏ có tên bool().

Đây thường là cách một biến cờ hoạt động. Ví dụ:

[ -d "$dir" ] || dir=

Trường hợp các phần khác của tập lệnh chỉ cần tìm bất kỳ giá trị nào $dirđể đánh giá mức độ hữu dụng của tập lệnh. Điều này cũng có ích khi liên quan đến việc thay thế tham số - vì các tham số có thể được mở rộng thành giá trị mặc định để điền vào chỗ trống hoặc không đặt, nhưng nếu không sẽ mở rộng thành giá trị đặt trước như ...

for set in yes ''
do echo "${set:-unset or null}"
done

... sẽ in ...

yes
unset or null

Tất nhiên, cũng có thể làm ngược lại :+nhưng điều đó chỉ có thể cung cấp cho bạn một mặc định đặt trước hoặc không có gì cả, trong khi mẫu ở trên có thể cung cấp cho bạn một giá trị hoặc giá trị mặc định.

Và liên quan đến ba lựa chọn - bất kỳ lựa chọn nào cũng có thể hoạt động tùy thuộc vào cách bạn chọn thực hiện nó. Trả về của hàm là tự kiểm tra, nhưng, nếu trả về đó cần tiết kiệm vì bất kỳ lý do gì, sẽ cần phải được đặt trong một biến. Nó phụ thuộc vào trường hợp sử dụng - là giá trị boolean bạn muốn đánh giá một bài kiểm tra một lần và loại được thực hiện? Nếu vậy, làm chức năng, một trong hai người kia có lẽ là cần thiết.


1
Tôi không nghĩ bạn đang trả lời câu hỏi của tôi. Tôi không hỏi làm thế nào booleans có thể được sử dụng trong tập lệnh shell, nhưng cách nào là phổ biến nhất và sẽ được người dùng khác mong đợi. Nếu câu hỏi của tôi không rõ ràng, tôi sẽ vui lòng chỉnh sửa nó. Ngoài ra một lời giải thích ngắn cho những gì câu trả lời của bạn sẽ là tốt đẹp. Cảm ơn bạn.
Minix

@Minix nào tốt hơn?
mikeerv

Tôi thường chỉ định truehoặc falsecho một biến, sau đó bạn có thể làmif $variable; then ...
wurtel

@wurtel - dựa trên mặc định $IFS- và nếu giá trị của var có thể chứa bất kỳ loại đầu vào nào của người dùng, thì cũng may mắn. Nếu giá trị không được biết đến để bắt đầu thì không cần phải kiểm tra nó. An toàn hơn bạn có thể làm if ${var:+":"} false; thenkhi làm việc với các giá trị null / không null. Nhưng điều đó hiếm khi hữu ích hơn[ -n "$var" ] &&
mikeerv

Nếu tôi khởi động tập lệnh của mình variable=falsevà sau đó đặt nó thành đúng theo bất kỳ điều kiện nào (giống như khi tôi sử dụng một biến trong C) thì không có vấn đề gì, nỗi ám ảnh của bạn với các giá trị IFS khác nhau và các giá trị biến ngẫu nhiên, v.v. .
wurtel

4

Trong bashmỗi biến về cơ bản là một chuỗi (hoặc một mảng hoặc một hàm, nhưng hãy nói về các biến thông thường ở đây).

Các điều kiện được phân tích cú pháp dựa trên các giá trị trả về của các lệnh kiểm tra - giá trị trả về không phải là một biến, đó là trạng thái thoát. Khi bạn đánh giá if [ ... ]hoặc if [[ ]]hoặc if grep somethingbất cứ thứ gì tương tự, giá trị trả về 0 (không phải chuỗi 0, nhưng trạng thái thoát 0 = thành công) có nghĩa là đúng và phần còn lại có nghĩa là sai (vì vậy, hoàn toàn ngược lại với ngôn ngữ lập trình được biên dịch, nhưng vì có một cách để thành công và nhiều cách để thất bại, và kết quả thực hiện dự kiến ​​thường là thành công, 0 được sử dụng làm kết quả mặc định phổ biến nhất nếu không có gì sai). Điều này rất hữu ích vì bất kỳ nhị phân nào cũng có thể được sử dụng làm thử nghiệm - nếu thất bại, đó là sai, nếu không thì đúng.

truefalsecác chương trình (thường bị ghi đè bởi nội dung) chỉ là những chương trình nhỏ không có tác dụng gì - truethành công khi không làm gì và thoát ra 0, trong khi falsecố gắng không làm gì và "thất bại", thoát ra 1. Nghe có vẻ vô nghĩa nhưng rất tiện cho việc viết kịch bản.

Đối với cách vượt qua sự thật lòng, điều đó tùy thuộc vào bạn. Điều khá phổ biến là chỉ sử dụng "y" hoặc "có" cho sự thật và sử dụng if [ x"$variable" = x"yes" ](nối thêm chuỗi giả xvì nếu $variabletình cờ có độ dài bằng không, điều này bảo vệ khỏi việc tạo một lệnh không có thật if [ = "yes" ]mà không phân tích cú pháp). Cũng có thể hữu ích khi chỉ cần sử dụng một chuỗi rỗng cho sai và sử dụng [ -z "$variable ]để kiểm tra xem nó có độ dài bằng không (hoặc -ncho nó là khác không).

Dù sao, thực sự rất hiếm khi cần phải vượt qua các giá trị boolean bash- đơn giản hơn là chỉ đơn giản là exitthất bại, hoặc trả về một kết quả hữu ích (hoặc bằng 0 nếu có sự cố và kiểm tra chuỗi rỗng), và hầu hết các trường hợp đều có thể kiểm tra thất bại trực tiếp từ statatus thoát.


Trong trường hợp của bạn, bạn muốn một hàm sẽ hoạt động như bất kỳ lệnh nào khác (do đó, trả về 0 khi thành công), vì vậy tùy chọn cuối cùng của bạn có vẻ là lựa chọn đúng.

Ngoài ra, bạn thậm chí có thể không cần returntuyên bố. Nếu hàm đủ đơn giản, bạn có thể sử dụng thực tế là nó chỉ trả về trạng thái của lệnh được thực hiện cuối cùng trong hàm. Vì vậy, chức năng của bạn có thể chỉ đơn giản là

drive_xyz_available() {
   [ -e /dev/disk/by-uuid/whatever ]
}

nếu bạn đang kiểm tra sự tồn tại của một nút thiết bị (hoặc grep /proc/mountsđể kiểm tra xem nó có được gắn không?).


Đó là một bản tóm tắt rất hay, cảm ơn bạn đã dành thời gian để viết nó lên. Tôi có thể suy luận từ đoạn cuối của bạn, rằng bạn sẽ xem xét tùy chọn drive_xyz_available()là phổ biến nhất không?
Minix

Bạn có thể cung cấp một số ví dụ cho y = truetrường hợp phổ biến ? Theo kinh nghiệm của tôi, hầu hết các tập lệnh trình bao bọc kiểm tra bất kỳ giá trị không null nào để xem nó là đúng - ít nhất là khi các biến môi trường được giải thích có liên quan. Nếu không, họ bỏ qua xe vỏ hoàn toàn.
mikeerv

3
Chuỗi giả cho ifthử nghiệm là không cần thiết nếu biến được trích dẫn; if [ "$variable" = "yes" ]hoạt động tốt ngay cả khi biến $ không được đặt.
daniel kullmann 19/2/2015

-2

Về cơ bản, bất kỳ số nào không phải là 0 là đúng và 0 là sai. Lý do trả về các giá trị là 0 cho một kết thúc thành công của tập lệnh hoặc bất kỳ số nào khác để xác định loại lỗi khác nhau.

$? sẽ trả về mã thoát của lệnh / thực thi trước đó, là 0 thành công và bất kỳ số nào khác lỗi đã được trả về.

Vì vậy, tôi sẽ sử dụng phương pháp đó cho đúng / sai. if (( ! $? ));then OK;else NOOK;fi


Sau đó, tôi sẽ viết một cho lựa chọn cuối cùng. Cảm ơn bạn.
Minix

5
Một số khác không thực sự là sai và số không là đúng. Chỉ cần nhìn vào đầu ra của true; echo $?false; echo $?.
Ruslan

@Ruslan. Bạn đã kiểm tra đầu ra của lệnh của tôi? Tôi đoán bạn đã không làm, nếu không bạn sẽ không nói những gì bạn đã làm. 0 là sai, bất kỳ số nào khác là đúng, lý do để phủ nhận !kết quả cho nó là TRUE. Kết quả từ một lệnh là 0 khi nó kết thúc chính xác, điều đó không có nghĩa là 0 là đúng. Từ truecó thể là 0, nhưng 0 không bao giờ đúng như ifđiều kiện thể hiện.
YoMismo

Điều đó giống như nói rằng trong C / C ++, 0truebởi vì if(!x){True();}else{False();}sẽ gọi True()khi nào x==0. Nhưng kiểm tra chính xác sẽ không !x, nhưng đúng hơn !!x.
Ruslan

Bạn đang waaaaaaay sai. Tôi không nói về thứ gì và thứ tự nào có bất cứ thứ gì bạn viết sau khi iftôi chỉ nêu thực tế rằng ở đây (trong bash, hoặc ksh, hoặc tsh, hoặc ....) như trong C / C ++, 0 là FALSE, bất kỳ số khác là TRUE, như bạn có thể đọc trong liên kết tiếp theo, các cài đặt ban đầu của C không cung cấp kiểu boolean, được định nghĩa là ints trong đó 0 là FALSE và 1 TRUE en.wikipedia.org/wiki/Boolean_data_type .
YoMismo
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.