Значення помилки "[: занадто багато аргументів" від if [] (квадратні дужки)


211

Я не зміг знайти жодного простого прямого ресурсу, який би змістив значення та виправив наступну помилку оболонки BASH, тому я розміщую те, що знайшов після дослідження.

Помилка:

-bash: [: too many arguments

Google-Версія: bash open square bracket colon too many arguments .

Контекст: умова if у квадратних дужках з простим оператором порівняння, рівним, більшим, ніж тощо, наприклад:

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

1
Де код, який спричинив цю конкретну помилку?
Anderson Green

Відповіді:


353

Якщо ваш $VARIABLEрядок містить пробіли або інші спеціальні символи, і використовуються одинарні квадратні дужки (що є ярликом для testкоманди), то рядок може бути розбита на кілька слів. Кожне з них трактується як окремий аргумент.

Так що одна змінна розділена на багато аргументів :

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

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

Те саме буде справедливо для будь-якого виклику функції, який висуває рядок, що містить пробіли або інші спеціальні символи.


Легке виправлення

Оберніть змінний вихід у подвійні лапки, змусивши його залишатися як один рядок (отже, один аргумент). Наприклад,

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

Просто як це. Але перейдіть до пункту "Також будьте обережні ...", якщо ви також не можете гарантувати, що ваша змінна не буде порожньою рядком або рядком, що не містить нічого, крім пробілу.


Або альтернативним виправленням є використання подвійних квадратних дужок (що є ярликом для new testкоманди).

Однак це існує лише в bash (і, мабуть, korn і zsh), і тому може бути не сумісно з оболонками за замовчуванням, викликаними і /bin/shт.д.

Це означає, що в деяких системах воно може працювати з консолі, але не тоді, коли викликається в іншому місці, як-отcron , залежно від того, як все налаштовано.

Це виглядатиме так:

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

Якщо ваша команда містить подвійні квадратні дужки на кшталт цього, і ви отримуєте помилки в журналах, але це працює з консолі, спробуйте замінити на [[запропоновану тут альтернативу або переконайтеся, що все, що виконує ваш сценарій, використовує оболонку, яка підтримує [[ака new test.


Також остерігайтесь [: unary operator expectedпомилки

Якщо ви бачите помилку "занадто багато аргументів", швидше за все, ви отримаєте рядок з функції з непередбачуваним результатом. Якщо також можливо отримати порожній рядок (або всю рядок пробілів), це трактуватиметься як нульовий аргумент навіть із вищевказаним "швидким виправленням", і не вдасться з[: unary operator expected

Це те саме "gotcha", якщо ви звикли до інших мов - ви не очікуєте, що вміст змінної буде ефективно надруковано в код, як цей, перш ніж він буде оцінений.

Ось приклад, який запобігає [: too many argumentsі [: unary operator expectedпомилки, і помилки: заміна виводу значенням за замовчуванням, якщо він порожній (у цьому прикладі 0), подвійними лапками, обернутими навколо всього:

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

(тут дія відбудеться, якщо $ VARIABLE дорівнює 0, або порожній. Природно, ви повинні змінити 0 (значення за замовчуванням) на інше значення за замовчуванням, якщо потрібна інша поведінка)


Остаточне зауваження: оскільки [це ярлик для test, все вищезазначене також стосується помилки test: too many arguments(а також test: unary operator expected)


Ще кращий спосібi=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So

1
У мене виникла проблема, коли Shellscript, що використовує BASH як інтерпретатор, коли виконувався через термінал, ставав у порядку, але коли виконувався через Crontab, виникали подібні помилки і надсилався локальний електронний лист через Postfix, повідомляючи про цю помилку, і я зрозумів, що там a IF для змінної, яка мала спеціальні символи. Подвійні цитати врятували мені життя. Дякую :)!
ivanleoncz

13

Просто наткнувся на цей пост, отримавши ту ж помилку, намагаючись перевірити , якщо дві змінні як порожній (або не порожньо). Це виявляється складним порівнянням - 7,3. Інші оператори порівняння - Розширений посібник із написання сценарію ; і я подумав, що слід зазначити наступне:

  • Я -eдумав, що спочатку це означає "порожньо"; але це означає "файл існує" - використовувати -zдля тестування порожньої змінної (рядок)
  • Строкові змінні потрібно цитувати
  • Для складеного логічного І порівняння:
    • використовувати два tests та &&їх:[ ... ] && [ ... ]
    • або використовувати -aоператора в одному test:[ ... -a ... ]

Ось робоча команда (пошук усіх файлів txt у каталозі та скидання тих, що grepзнаходять, містять обидва слова):

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

Редагувати 12 серпня 2013 року: відповідна примітка щодо проблеми:

Зауважте, що при перевірці рівності рядків з класичним test(одна квадратна дужка [), ВАМ ПОВИННІ мати пробіл між оператором "дорівнює", що в цьому випадку є єдиним =знаком "рівності" (хоча два знаки рівності ==здаються прийнятими як рівність оператор теж). Таким чином, це не вдається (мовчки):

$ 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

... але додайте пробіл - і все виглядає добре:

$ 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

Не могли б ви надати приклад оболонки башти ((A || B) && C)?
jww

дивіться питання 3826425 та 14964805
splaisan

Це дійсно не так корисно для відповіді, оскільки це не показує вам, як повністю містити команду в квадратних дужках, яка потрібна, наприклад, якщо є цикл.
Тимофій Лебедь

5

Ще один сценарій, до якого можна отримати [: too many argumentsабо [: a: binary operator expectedпомилки, - це якщо ви спробуєте перевірити всі аргументи"$@"

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

Вона працює правильно , якщо ви телефонуєте foo.shабо foo.sh arg1. Але якщо ви передасте кілька аргументів на кшталт foo.sh arg1 arg2, ви отримаєте помилки. Це тому, що він розширюється на [ -z arg1 arg2 ], що не є коректним синтаксисом.

Правильний спосіб перевірити наявність аргументів - це [ "$#" -eq 0 ]. ( $#це кількість аргументів).


2

Інколи Якщо ви випадково торкаєтесь клавіатури та видаляєте пробіл.

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

Запустить це повідомлення про помилку Зверніть увагу на пробіл перед введенням]].


1
Я думаю, що це призводить до різної синтаксичної помилки, наприклад: рядок 21: [: відсутній `] '
Джо Холлоуей

1

У мене були такі ж проблеми зі своїми сценаріями. Але коли я зробив деякі модифікації, це працювало на мене. Мені було так: -

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

таким чином я вирішив свою проблему. Сподіваюся, що це теж допоможе вам.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.