Ý nghĩa của từ [: quá nhiều đối số Lỗi lỗi từ if [] (dấu ngoặc vuông)


211

Tôi không thể tìm thấy bất kỳ tài nguyên đơn giản đơn giản nào đánh vần ý nghĩa và sửa lỗi lỗi BASH sau đây, vì vậy tôi sẽ đăng những gì tôi tìm thấy sau khi nghiên cứu về nó.

Lỗi:

-bash: [: too many arguments

Phiên bản thân thiện với Google : bash open square bracket colon too many arguments .

Bối cảnh: một điều kiện if trong ngoặc vuông đơn với toán tử so sánh đơn giản như bằng, lớn hơn vv, ví dụ:

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 

1
Mã sản xuất lỗi cụ thể này ở đâu?
Anderson Green

Câu trả lời:


353

Nếu $VARIABLEchuỗi của bạn là một chuỗi chứa khoảng trắng hoặc các ký tự đặc biệt khác và dấu ngoặc vuông đơn được sử dụng (là lối tắt cho testlệnh), thì chuỗi có thể được chia thành nhiều từ. Mỗi trong số này được coi là một đối số riêng biệt.

Vì vậy, một biến được chia thành nhiều đối số :

VARIABLE=$(/some/command);  
# returns "hello world"

if [ $VARIABLE == 0 ]; then
  # fails as if you wrote:
  # if [ hello world == 0 ]
fi 

Điều tương tự cũng sẽ đúng với bất kỳ lệnh gọi hàm nào đặt chuỗi chứa khoảng trắng hoặc các ký tự đặc biệt khác.


Dễ dàng sửa chữa

Gói đầu ra biến trong dấu ngoặc kép, buộc nó ở lại dưới dạng một chuỗi (do đó là một đối số). Ví dụ,

VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
  # some action
fi 

Đơn giản như vậy. Nhưng bỏ qua "Cũng hãy cẩn thận ..." bên dưới nếu bạn cũng không thể đảm bảo biến của mình sẽ không phải là một chuỗi trống hoặc một chuỗi không chứa gì ngoài khoảng trắng.


Hoặc, một sửa chữa thay thế là sử dụng dấu ngoặc vuông đôi (là một phím tắt cho new testlệnh).

Tuy nhiên, điều này chỉ tồn tại trong bash (và rõ ràng là korn và zsh), và do đó có thể không tương thích với các shell mặc định được gọi bởi /bin/shv.v.

Điều này có nghĩa là trên một số hệ thống, nó có thể hoạt động từ bàn điều khiển nhưng không phải khi được gọi ở nơi khác, như từcron , tùy thuộc vào cách mọi thứ được cấu hình.

Nó sẽ trông như thế này:

VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
  # some action
fi 

Nếu lệnh của bạn chứa dấu ngoặc vuông như thế này và bạn gặp lỗi trong nhật ký nhưng nó hoạt động từ bảng điều khiển, hãy thử hoán đổi [[một thay thế được đề xuất ở đây, hoặc, đảm bảo rằng bất cứ điều gì chạy tập lệnh của bạn đều sử dụng shell hỗ trợ [[aka new test.


Cũng hãy cẩn thận với [: unary operator expectedlỗi

Nếu bạn thấy lỗi "quá nhiều đối số", rất có thể bạn đang nhận được một chuỗi từ một hàm có đầu ra không thể đoán trước. Nếu cũng có thể có được một chuỗi rỗng (hoặc tất cả các chuỗi khoảng trắng), thì điều này sẽ được coi là đối số bằng 0 ngay cả với "sửa chữa nhanh" ở trên và sẽ thất bại với[: unary operator expected

Nó giống như 'gotcha' nếu bạn đã sử dụng các ngôn ngữ khác - bạn không mong muốn nội dung của một biến được in một cách hiệu quả vào mã như thế này trước khi nó được đánh giá.

Đây là một ví dụ ngăn cả lỗi [: too many arguments[: unary operator expectedlỗi: thay thế đầu ra bằng giá trị mặc định nếu nó trống (trong ví dụ này 0), với dấu ngoặc kép được bao quanh toàn bộ:

VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
  # some action
fi 

(ở đây, hành động sẽ xảy ra nếu $ VARIABLE bằng 0 hoặc trống. Đương nhiên, bạn nên thay đổi 0 (giá trị mặc định) thành giá trị mặc định khác nếu muốn có hành vi khác)


Lưu ý cuối cùng:[là một phím tắt cho test, tất cả những điều trên cũng đúng với lỗi test: too many arguments(và cả test: unary operator expected)


Một cách thậm chí tốt hơn lài=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So

1
Tôi đã gặp sự cố khi Shellscript sử dụng BASH làm thông dịch viên, khi được thực thi qua thiết bị đầu cuối, sẽ ổn, nhưng khi thực hiện qua Crontab, đã gặp lỗi như thế này và gửi email cục bộ qua Postfix, thông báo lỗi này và tôi đã nhận ra rằng một IF cho một biến có các ký tự đặc biệt. Báo giá đôi đã cứu cuộc đời tôi. Cảm ơn bạn :)!
ivanleoncz

13

Chỉ tình cờ gặp bài này, bằng cách nhận các lỗi tương tự, cố gắng để kiểm tra nếu hai biến là cả rỗng (hoặc không có sản phẩm nào). Điều đó hóa ra là một so sánh ghép - 7.3. Các toán tử so sánh khác - Hướng dẫn Bash-Scripting nâng cao ; và tôi nghĩ tôi nên lưu ý những điều sau:

  • Lúc đầu tôi đã -enghĩ nó có nghĩa là "trống rỗng"; nhưng điều đó có nghĩa là "tập tin tồn tại" - sử dụng -zđể kiểm tra biến rỗng (chuỗi)
  • Các biến chuỗi cần được trích dẫn
  • Để so sánh logic và so sánh, một trong hai:
    • sử dụng hai tests và &&chúng:[ ... ] && [ ... ]
    • hoặc sử dụng -atoán tử trong một test:[ ... -a ... ]

Đây là một lệnh làm việc (tìm kiếm thông qua tất cả các tệp txt trong một thư mục và loại bỏ những thứ greptìm thấy có chứa cả hai từ):

find /usr/share/doc -name '*.txt' | while read file; do \
  a1=$(grep -H "description" $file); \
  a2=$(grep -H "changes" $file); \
  [ ! -z "$a1" -a ! -z "$a2"  ] && echo -e "$a1 \n $a2" ; \
done

Chỉnh sửa ngày 12 tháng 8 năm 2013: lưu ý vấn đề liên quan:

Lưu ý rằng khi kiểm tra sự bằng nhau của chuỗi với cổ điển test(dấu ngoặc đơn [), bạn PHẢI có khoảng trắng giữa toán tử "bằng", trong trường hợp này là một dấu "bằng" duy nhất =(mặc dù hai dấu bằng ==có vẻ được chấp nhận là đẳng thức Toán tử cũng vậy). Do đó, điều này thất bại (âm thầm):

$ if [ "1"=="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi 
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi 
A

... nhưng thêm không gian - và tất cả có vẻ tốt:

$ if [ "1" = "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi 
B

Bạn có thể cung cấp một ví dụ bash shell của ((A || B) && C)?
jww

vui lòng xem câu hỏi 382642514964805
splaisan

Điều này thực sự không hữu ích cho câu trả lời vì nó không chỉ cho bạn cách chứa lệnh hoàn toàn trong dấu ngoặc vuông, điều cần thiết nếu có một vòng lặp, chẳng hạn.
Timothy Swan

5

Một kịch bản khác mà bạn có thể gặp phải [: too many argumentshoặc [: a: binary operator expectedlỗi là nếu bạn cố kiểm tra tất cả các đối số"$@"

if [ -z "$@" ]
then
    echo "Argument required."
fi

Nó hoạt động chính xác nếu bạn gọi foo.shhoặc foo.sh arg1. Nhưng nếu bạn vượt qua nhiều đối số như thế foo.sh arg1 arg2, bạn sẽ gặp lỗi. Điều này là do nó đang được mở rộng [ -z arg1 arg2 ], đây không phải là một cú pháp hợp lệ.

Cách chính xác để kiểm tra sự tồn tại của các đối số là [ "$#" -eq 0 ]. ( $#là số lượng đối số).


2

Một số lần Nếu bạn vô tình chạm vào bàn phím và xóa một khoảng trắng.

if [ "$myvar" = "something"]; then
    do something
fi

Sẽ kích hoạt thông báo lỗi này. Lưu ý không gian trước ']' là bắt buộc.


1
Tôi nghĩ rằng điều đó dẫn đến một lỗi cú pháp khác nhau, chẳng hạn như: dòng 21: [: thiếu `] '
Joe Holloway

1

Tôi đã có vấn đề tương tự với các kịch bản của tôi. Nhưng khi tôi thực hiện một số sửa đổi, nó đã làm việc cho tôi. Tôi đã làm như thế này: -

export k=$(date "+%k");
if [ $k -ge 16 ] 
    then exit 0; 
else 
    echo "good job for nothing"; 
fi;

bằng cách đó tôi đã giải quyết vấn đề của mình Hy vọng rằng sẽ giúp cho bạn quá.

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.