Shell: Sử dụng hàm với tham số trong if


8

Tôi đang cố thực thi mã bên dưới nhưng khi tôi cố gắng sử dụng hàm của mình trong câu lệnh if thì tôi gặp -bash: [: too many argumentslỗi. Tại sao nó lại xảy ra?

Cảm ơn bạn trước!

notContainsElement () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 1; done
  return 0
}

list=( "pears" "apples" "bananas" "oranges" )
blacklist=( "oranges" "apples" )
docheck=1

for fruit in "${list[@]}"
do
    if [ notContainsElement "$fruit" "${blacklist[@]}" -a $docheck = 1 ]
    then
        echo $fruit
    fi
done

1
Sử dụng shellcheck.net (hoặc phiên bản ngoại tuyến của nó). Nó tìm thấy vấn đề được đề cập trong các câu trả lời mặc dù với một lời giải thích ít chi tiết hơn và không có giải pháp.
David Foerster

Câu trả lời:


14

Khi sử dụng, if [ ... ]bạn thực sự đang sử dụng [tiện ích (tương tự testnhưng yêu cầu đối số cuối cùng là ]).

[không hiểu để chạy chức năng của bạn, nó mong đợi chuỗi. May mắn thay, bạn không cần phải sử dụng [tất cả ở đây (ít nhất là cho chức năng):

if [ "$docheck" -eq 1 ] && notContainsElement "$fruit" "${blacklist[@]}"; then
  ...
fi

Lưu ý rằng trước tiên tôi cũng kiểm tra số nguyên, do đó chúng tôi có thể tránh gọi hàm nếu $docheckkhông phải là 1.

Điều này hoạt động vì ifcó một lệnh tùy ý và quyết định phải làm gì từ trạng thái thoát của lệnh đó. Ở đây chúng tôi sử dụng một [ ... ]bài kiểm tra cùng với một cuộc gọi đến chức năng của bạn, với &&phần giữa, tạo ra một lệnh ghép. Trạng thái thoát của lệnh ghép sẽ là đúng nếu cả [ ... ]phép thử và hàm trả về 0 là trạng thái thoát của chúng, báo hiệu thành công.

Là một phong cách lưu ý, tôi sẽ không có xét nghiệm chức năng dù mảng nào không chứa nguyên tố này nhưng cho dù nếu không chứa nguyên tố này, và sau đó

if [ "$docheck" -eq 1 ] && ! contains "$fruit" "${blacklist[@]}"; then ...

Có một thử nghiệm chức năng một ý chí lộn xộn tiêu cực lên logic trong trường hợp bạn làm muốn kiểm tra xem mảng chứa các phần tử ( if ! notContainsElement ...).


Cảm ơn bạn rất nhiều vì câu trả lời và những lời khuyên khác!
Andrea Silvestri

3

thử

if notContainsElement "$fruit" "${blacklist[@]}" && test "$docheck" = 1
then
  • -atùy chọn không phải là vỏ hoặc testtùy chọn

ở đây bạn có hai phần kiểm tra

notContainsElement "$fruit" "${blacklist[@]}"
test $docheck = 1 ## or [ $docheck = 1 ]

bạn liên kết sau đó ifsử dụng

if cmd1 && cmd2

như đã chỉ ra -alà một tùy chọn thử nghiệm, nhưng chỉ có thể được sử dụng với tùy chọn thử nghiệm khác, do đó bạn có thể sử dụng

if [ "$a" -lt "$b" -a "$a" -lt "$c" ]

để kiểm tra $amức thấp hơn cả hai $b$c, nhưng bạn không thể sử dụng lệnh khác trong phạm vi kiểm tra.


arg, @Kusalananda là khẩu súng nhanh nhất trên thế giới hoang dã một lần nữa;)
Archemar 13/07/18

RSI là giá tôi phải trả cho điều đó.
Kusalananda

-alà tùy chọn thử nghiệm , nó có nghĩa là VÀ.
hyde

@hyde Ngoại trừ nó đã được đánh dấu lỗi thời trong tiêu chuẩn POSIX.
Kusalananda

1
@Archemar, ... xem xét sửa các lỗi trích dẫn vẫn có trong các ví dụ của bạn (không trích dẫn $docheck, không trích dẫn $a/ $b/ etc trong ví dụ trước).
Charles Duffy

0

Đây là một thay thế mà một số người có thể không thích. Chuyển đổi mảng danh sách đen của bạn thành một chuỗi và xem chuỗi có loại bỏ trái cây có giống nhau không. Chỉnh sửa để đệm các chuỗi với không gian. Cảm ơn Scott đã chỉ ra vấn đề táo / dứa.

badlist=" ${blacklist[@]} "
for f in "${list[@]}"
do
    if [[ "${badlist/" $f "/}" == "$badlist" ]]
    then
        echo "$f"
    fi
done

Tôi nghĩ rằng điều này đơn giản hơn, nhưng thiếu logic && mà nhiều người thích.


(1) Điều này thất bại trong trường hợp một trong những listloại trái cây được chứa trong một trong những blacklistloại trái cây. Ví dụ: nếu chúng tôi thay đổi blacklistthành ( "oranges" "pineapples" ), đầu ra của tập lệnh của bạn sẽ không thay đổi. Tiết (Cont'd)
Scott

(Tiếp theo), (2) Tôi không hiểu ý của bạn là gì bởi tôi nghĩ điều này đơn giản hơn, nhưng lại thiếu && logic mà nhiều người thích. Nó thường dễ dàng hơn để làm cho mọi thứ đơn giản hơn bằng cách loại bỏ chức năng. Như Albert Einstein có thể hoặc không thể nói, mọi thứ nên được làm đơn giản nhất có thể, nhưng không đơn giản hơn. Tại sao bạn rời khỏi &&? (3) Khi bạn đăng mã, xin vui lòng thụt lề một cách thích hợp.
Scott

Chà, tôi đã thử sử dụng thụt lề 4 không gian nhưng có vẻ như nó không hoạt động. Tôi thấy những gì bạn có ý nghĩa về dứa, mặc dù.
Wastrel

Nó cũng không thể phân biệt giữa một mục danh sách đơn two words, và hai mục tiếp theo, twowords. Và nếu danh sách của bạn chứa *dưới dạng một mục, nó sẽ khớp với mọi thứ. (Và vì bạn không trích dẫn $fnội dung nên là gì echo "$f", nếu bạn đã cố gắng lặp lại một phần tử như vậy, nó sẽ được thay thế bằng một danh sách tên tệp trong thư mục hiện tại).
Charles Duffy

Tôi đã thực hiện một số chỉnh sửa. Điều này không phải là nhỏ khi dữ liệu trong các mảng là tùy ý. Giả sử "táo" nằm trong danh sách đen và "táo Granny Smith" là một yếu tố của mảng khác. Tôi nghĩ mã của OP có vấn đề tương tự. Các mảng phải được làm bằng các yếu tố "hoạt động."
Wastrel
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.