Tại sao không sử dụng nhiều lệnh với một | | hoặc && công việc có điều kiện?


12

Điều này hoạt động trên một dấu nhắc shell (bash, dash):

[ -z "" ] && echo A || echo B
A

Tuy nhiên, tôi đang cố gắng viết một kịch bản shell POSIX , nó bắt đầu như thế này:

#!/bin/sh

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

readonly raw_input_string=${1}

[ -z "${raw_input_string}" ] && echo "The given argument is empty."; exit 1

Và tôi không biết tại sao, nhưng tôi không nhận được tin nhắn :

Đối số đã cho là trống rỗng.

nếu tôi gọi kịch bản như thế này:

./test_empty_argument ""

Tại sao vậy?


5
Xem Làm thế nào tôi có thể kiểm tra nếu một biến trống hoặc chỉ chứa khoảng trắng? để biết cách kiểm tra nếu một biến trống, không đặt hoặc chỉ chứa khoảng trống. Vấn đề trong câu hỏi này không có gì để làm với điều đó.
ilkkachu

1
Chỉ cần sử dụngif [ X”” = X”$var” ] ; then echo isempty ; fi
user2497

3
@ user2497 Không có lý do để sử dụng nó trong bất kỳ shell nào được phát hành trong 20 năm qua. Đó là một cách giải quyết cho các vỏ cũ, lỗi.
chepner

@chepner Vậy nó không phải là giải pháp hợp lệ? Cái gì khác phải được sử dụng?
user2497

6
[ "" = "$var" ]sẽ làm việc tốt; một chuỗi rỗng được trích dẫn sẽ không bị xóa khỏi danh sách đối số [. Nhưng điều đó cũng không cần thiết, bởi vì nó [ -z "$var" ] cũng hoạt động tốt.
chepner

Câu trả lời:


37

Lưu ý rằng dòng của bạn

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

điều này giống như

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."
exit 1

(không được trích dẫn ; trong hầu hết các trường hợp, một ký tự không có thể được thay thế bằng một ký tự dòng mới)

Điều này có nghĩa là exit 1câu lệnh luôn được thực thi bất kể có bao nhiêu đối số được truyền cho tập lệnh. Đến lượt điều này có nghĩa là tin nhắn The given argument is empty.sẽ không bao giờ có cơ hội được in.

Để thực thi nhiều hơn một câu lệnh sau khi kiểm tra bằng "cú pháp ngắn mạch", hãy nhóm các câu lệnh vào { ...; }. Cách khác là sử dụng một ifcâu lệnh thích hợp (IMHO, trông gọn gàng hơn trong tập lệnh):

if [ "$#" -ne 1 ]; then
    echo 'Invalid number of arguments, expected one.' >&2
    exit 1
fi

Bạn có cùng một vấn đề với bài kiểm tra thứ hai của bạn.


Về

[ -z "" ] && echo A || echo B

Điều này sẽ làm việc cho ví dụ đã cho, nhưng chung chung

some-test && command1 || command2

sẽ không giống như

if some-test; then
    command1
else
    command2
fi

Thay vào đó, nó giống như

if ! { some-test && command1; }; then
    command2
fi

hoặc là

if some-test && command1; then
    :
else
    command2
fi

Đó là, nếu kiểm tra hoặc lệnh đầu tiên thất bại, lệnh thứ hai sẽ thực thi, có nghĩa là nó có khả năng thực thi cả ba câu lệnh liên quan.


18

Điều này:

[ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; exit 1

không phải:

[ "${#}" -eq 1 ] || { echo "Invalid number of arguments, expected one."; exit 1; }

Nhưng thay vào đó là:

{ [ "${#}" -eq 1 ] || echo "Invalid number of arguments, expected one."; } 
exit 1

Kịch bản của bạn đang thoát bất kể bạn đã chuyển bao nhiêu đối số cho nó.


8

Một cách để làm cho nó dễ đọc hơn là xác định diehàm (à la perl) như:

die() {
  printf >&2 '%s\n' "$@"
  exit 1
}

# then:

[ "$#" -eq 1 ] || die "Expected one argument, got $#"

[ -n "$1" ] || die "Empty argument not supported"

Bạn có thể thêm nhiều chuông và còi như màu sắc, tiền tố, số dòng ... nếu cần.


Trong thực tế, bạn có bao giờ gọi diehàm của bạn với nhiều đối số không? (Nếu vậy, bạn có thể đưa ra một ví dụ không?) Tôi sử dụng một diechức năng gần như giống hệt nhau , nhưng sử dụng "$*"thay vào đó, có thể là nhiều hơn những gì bạn đang có ý định?
jrw32982 hỗ trợ Monica

3
Giá trị của "$@"nó là cho phép tin nhắn nhiều dòng mà không cần thêm dòng mới.
Charles Duffy

1
@ jrw32982, sử dụng "$*"để tham gia args với khoảng trắng cũng có nghĩa là bạn cần đặt $IFSthành SPC để nó hoạt động trong tất cả các bối cảnh bao gồm cả những nơi $IFSđã được sửa đổi. Ngoài ra với ksh/ zsh, bạn có thể sử dụng print -r -- "$@"hoặc echo -E - "$@"trong zsh.
Stéphane Chazelas

@CharlesDuffy Có, nhưng tôi chưa bao giờ thấy điều đó được thực hiện trong ngữ cảnh của diehàm -type. Điều tôi đang hỏi là: trong thực tế, bạn đã bao giờ thấy ai viết die "unable to blah:" "some error", với mục đích nhận được thông báo lỗi 2 dòng chưa?
jrw32982 hỗ trợ Monica

@ StéphaneChazelas Điểm tốt. Vì vậy (trong công thức của tôi) nó nên được die() { IFS=" "; printf >&2 "%s\n" "$*"; exit 1; }. Bạn đã bao giờ sử dụng loại diehàm này để printftạo một thông báo lỗi nhiều dòng bằng cách truyền nhiều đối số chưa? Hay bạn chỉ bao giờ chuyển một đối số duy nhất để dienó chỉ thêm một dòng mới vào đầu ra của nó?
jrw32982 hỗ trợ Monica

-1

Tôi thường xem đây là một thử nghiệm cho một chuỗi trống:

if [ "x$foo" = "x" ]; then ...

Đáng lẽ phải là "=" - đã sửa.
wef

3
Thực tế đó là theo nghĩa đen từ những năm 1970. Không có lí do gì để sử dụng nó với bất kỳ vỏ đó là phù hợp với các tiêu chuẩn sh 1992 POSIX (miễn là đúng trích dẫn được sử dụng và chức năng bây giờ-nưa như -a, -o, ()như derectives nói testđể kết hợp nhiều hoạt động tại một invocation đơn được tránh; xem các dấu OB trong pubs.opengroup.org/onlinepub/9699919799/utilities/test.html ).
Charles Duffy

Các thông báo không phải của linux được vận chuyển với 'sh' ban đầu vào thập niên 90 - vẫn có thể làm được. Trong công việc của tôi tại thời điểm đó, tôi đã phải viết các kịch bản cài đặt di động và tôi đã sử dụng cấu trúc này. Tôi chỉ xem các tập lệnh cài đặt mà NVidia cung cấp cho linux và họ vẫn sử dụng cấu trúc này.
wef

NVidia có thể sử dụng nó, nhưng điều đó không có nghĩa là họ có bất kỳ biện minh kỹ thuật nào để làm như vậy; sự phát triển hàng hóa trong thương mại UNIX là rất phổ biến. Ngay cả Heirloom Bourne cũng không có lỗi trong câu hỏi - vì vậy, cơ sở mã hóa SunOS (là UNIX thương mại cuối cùng gửi một máy không phải POSIX /bin/sh, và người tiền nhiệm trực tiếp của Heirloom Bourne) cũng không có.
Charles Duffy

1
Tôi không đội mũ, vì vậy tôi không thể hứa đăng video YouTube ăn nó nếu ai đó bật vỏ được xuất bản trên UNIX thương mại với lỗi này sau năm 1990 ... nhưng nếu tôi làm vậy, nó sẽ rất hấp dẫn . :)
Charles Duffy
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.