Значение ошибки [: слишком много аргументов], если [] (квадратные скобки)

Я не смог найти какой-либо простой простой ресурс, излагающий смысл и исправление для следующей ошибки оболочки 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

Если ваш $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 

Если ваша команда содержит двойные квадратные скобки, подобные этой, и вы получаете ошибки в журналах, но она работает из консоли, попробуйте поменять [[ на альтернативу, предложенную здесь, или убедитесь, что при выполнении вашего скрипта используется оболочка поддерживает [[ aka new test.


Также остерегайтесь ошибки [: unary operator expected

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

Это то же самое "надо", если вы привыкли к другим языкам - вы не ожидаете, что содержимое переменной будет эффективно напечатано в коде, подобном этому, до его оценки.

Вот пример, который предотвращает как ошибки [: 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)

Ответ 2

Просто наткнулся на этот пост, получив ту же ошибку, пытаясь проверить, являются ли две переменные пустыми (или не пустыми). Это оказывается соединение сравнения - 7.3. Другие операторы сравнения - расширенный Bash -Scripting Guide; и я подумал, что должен отметить следующее:

  • Я использовал -e, думая, что сначала означает "пустой"; но это означает, что "файл существует" - используйте -z для проверки пустой переменной (строки)
  • Строковые переменные должны быть указаны
  • Для сложного логического И сравнения:
    • используйте два test и && их: [ ... ] && [ ... ]
    • или используйте оператор -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 (одиночная квадратная скобка [) вы MUST имеете пробел между оператором "равен", который в этом случае является одним Знак "равно" = (хотя два равнозначных знака ==, как представляется, также принимаются как оператор равенства). Таким образом, это терпит неудачу (молча):

$ 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

Ответ 3

Другой сценарий, в котором вы можете получить ошибки [: too many arguments или [: a: binary operator expected, - это попытка проверить все аргументы "[email protected]"

if [ -z "[email protected]" ]
then
    echo "Argument required."
fi

Это работает правильно, если вы позвоните foo.sh или foo.sh arg1. Но если вы передадите несколько аргументов, например foo.sh arg1 arg2, вы получите ошибки. Это потому, что он расширен до [ -z arg1 arg2 ], который не является допустимым синтаксисом.

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

Ответ 4

Несколько раз, если вы случайно коснулись клавиатуры и удалили пробел.

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

Появится это сообщение об ошибке. Обратите внимание на пробел перед ']'.

Ответ 5

У меня была такая же проблема с моими скриптами. Но когда я сделал некоторые изменения, это сработало для меня. Мне это понравилось: -

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

таким образом я решил свою проблему. Надеюсь, что это тоже поможет.