Lỗi tập lệnh bash [:! =: Toán tử một ngôi được mong đợi


96

Trong tập lệnh của mình, tôi đang cố gắng kiểm tra lỗi xem đối số đầu tiên và duy nhất có bằng -v không nhưng nó là đối số tùy chọn. Tôi sử dụng câu lệnh if nhưng tôi vẫn gặp lỗi dự kiến ​​toán tử một ngôi.

đây là mã:

if [ $1 != -v ]; then
   echo "usage: $0 [-v]"
   exit
fi

Biên tập:

Tôi nên nói cụ thể hơn: Phần này của tập lệnh ở trên đang kiểm tra một đối số tùy chọn và sau đó, nếu đối số không được nhập, nó sẽ chạy phần còn lại của chương trình.

#!/bin/bash

if [ "$#" -gt "1" ]; then
   echo "usage: $0 [-v]"
   exit
fi

if [ "$1" != -v ]; then
   echo "usage: $0 [-v]"
   exit
fi

if [ "$1" = -v ]; then
   echo "`ps -ef | grep -v '\['`"
else
   echo "`ps -ef | grep '\[' | grep root`"
fi

... nhân tiện, tôi nghĩ bạn muốn echo "usage: $0 [-v]"; $-hiển thị các cờ tùy chọn trình bao hoạt động, không phải tên của tập lệnh hiện tại.
Charles Duffy

Tôi có quyền đó, tôi muốn nó hiển thị tên của kịch bản hiện tại.
user3380240 Ngày

4
Chào mừng bạn đến với stackoverflow và đặc biệt là thẻ bash! Kiểm tra wiki thẻ để biết các công cụ và tài nguyên hữu ích, như shellcheck sẽ chỉ ra (mặc dù không phải lúc nào cũng giải thích) nhiều vấn đề như thế này.
đó là anh chàng khác

@ user3380240, $-không tên của kịch bản hiện hành. $0Là.
Charles Duffy

Xin lỗi, đó là một lỗi đánh máy.
user3380240 Ngày

Câu trả lời:


189

Báo giá!

if [ "$1" != -v ]; then

Ngược lại, khi $1hoàn toàn trống, thử nghiệm của bạn sẽ trở thành:

[ != -v ]

thay vì

[ "" != -v ]

... và !=không phải là toán tử một ngôi (nghĩa là toán tử chỉ có thể nhận một đối số duy nhất).


8
Hoặc, nếu bạn không lo ngại về tính di động, bạn có thể sử dụng dấu ngoặc kép, bên trong đó mở rộng biến không cần phải được trích dẫn: if [[ $1 != -v ]]; then
Mike Holt

@MikeHolt, thực sự - Tôi đưa ra điều đó trong một bình luận về câu hỏi, ở trên.
Charles Duffy

@DanielDinnyes, nếu IFS=1, sau đó [ $# -eq 1 ]sẽ không hoạt động tốt như vậy, trong khi nó [ "$#" -eq 1 ]hoạt động như dự định ngay cả sau đó. Đó là một trường hợp bệnh lý, chắc chắn, nhưng tốt hơn nên viết phần mềm không có chúng khi được lựa chọn.
Charles Duffy

-2

Hoặc đối với những gì có vẻ như tràn lan quá mức cần thiết, nhưng thực sự là đơn giản ... Khá nhiều bao gồm tất cả các trường hợp của bạn, và không có chuỗi rỗng hoặc mối quan tâm đơn lẻ.

Trong trường hợp đối số đầu tiên là '-v', sau đó thực hiện điều kiện của bạn ps -ef, còn lại trong tất cả các trường hợp khác thì sử dụng.

#!/bin/sh
case $1 in
  '-v') if [ "$1" = -v ]; then
         echo "`ps -ef | grep -v '\['`"
        else
         echo "`ps -ef | grep '\[' | grep root`"
        fi;;
     *) echo "usage: $0 [-v]"
        exit 1;; #It is good practice to throw a code, hence allowing $? check
esac

Nếu ai đó không quan tâm đối số '-v' ở đâu, thì chỉ cần bỏ trường hợp vào trong một vòng lặp. Nó sẽ cho phép đi bộ tất cả các args và tìm '-v' ở bất cứ đâu (miễn là nó tồn tại). Điều này có nghĩa là thứ tự đối số dòng lệnh không quan trọng. Hãy cảnh báo trước, như đã trình bày, biến arg_match được thiết lập, do đó nó chỉ là một cờ. Nó cho phép nhiều lần xuất hiện đối số '-v'. Người ta có thể bỏ qua tất cả các lần xuất hiện khác của '-v' đủ dễ dàng.

#!/bin/sh

usage ()
 {
  echo "usage: $0 [-v]"
  exit 1
 }

unset arg_match

for arg in $*
 do
  case $arg in
    '-v') if [ "$arg" = -v ]; then
           echo "`ps -ef | grep -v '\['`"
          else
           echo "`ps -ef | grep '\[' | grep root`"
          fi
          arg_match=1;; # this is set, but could increment.
       *) ;;
  esac
done

if [ ! $arg_match ]
 then
  usage
fi

Tuy nhiên, cho phép nhiều lần xuất hiện của một đối số thuận tiện để sử dụng trong các tình huống như:

$ adduser -u:sam -s -f -u:bob -trace -verbose

Chúng tôi không quan tâm đến thứ tự của các đối số và thậm chí cho phép nhiều đối số -u. Vâng, nó là một vấn đề đơn giản cũng cho phép:

$ adduser -u sam -s -f -u bob -trace -verbose

$*không nên được sử dụng trong ngữ cảnh này: Nó nối các mục thành một chuỗi vừa được tách chuỗi vừa được mở rộng toàn cầu; không giống như "$@", để lại các mục với giá trị ban đầu chính xác của chúng. Và bạn đang thiếu một số trích dẫn, shellcheck.net sẽ bắt được (với các cảnh báo được liên kết với trang wiki mô tả lý do tại sao những trích dẫn đó lại quan trọng).
Charles Duffy

Xem xét, như một ví dụ cụ thể, -U'Bob Barker'; for arg in $*sẽ xem nó như là -UBobvà sau đó Barkerlà một mục riêng biệt; trong khi for item in "$@"sẽ xem -UBob Barkernhư một chuỗi đơ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.