Значение ошибки "[: too many arguments" от if [] (квадратные скобки)
Я не смог найти ни одного простого и понятного ресурса, в котором было бы разъяснено значение и исправлена следующая ошибка оболочки 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
6 ответов
Если твой $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
Также остерегайтесь [: 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
)
Просто наткнулся на этот пост, получая ту же ошибку, пытаясь проверить, являются ли две переменные обе пустыми (или непустыми). Это оказывается сложным сравнением - 7.3. Другие операторы сравнения - Расширенное руководство по написанию сценариев; и я подумал, что должен отметить следующее:
- я использовал
-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
(одна квадратная скобка [
), вы ДОЛЖНЫ иметь пробел между оператором "равно", который в данном случае является одним "равно" =
знак (хотя два знака равенства ==
похоже, тоже принимаются как оператор равенства). Таким образом, это терпит неудачу (молча):
$ 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
Другой сценарий, который вы можете получить [: 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 ]
. ($#
количество аргументов).
Я тоже столкнулся с той же проблемой. Ответ @sdaau помог мне логически. Вот что я делал, что кажется мне синтаксически правильным, но получал ошибку слишком много аргументов.
Неправильный синтаксис:
if [ $Name != '' ] && [ $age != '' ] && [ $sex != '' ] && [ $birthyear != '' ] && [ $gender != '' ]
then
echo "$Name"
echo "$age"
echo "$sex"
echo "$birthyear"
echo "$gender"
else
echo "Enter all the values"
fi
в приведенном выше заявлении if, если я передаю значения переменной, как указано ниже, тогда я также получал синтаксическую ошибку
export "Name"="John"
export "age"="31"
export "birthyear"="1990"
export "gender"="M"
С синтаксисом ниже я получаю ожидаемый результат. Правильный синтаксис:
if [ "$Name" != "" -a "$age" != "" -a "$sex" != "" -a "$birthyear" != "" -a "$gender" != "" ]
then
echo "$Name"
echo "$age"
echo "$sex"
echo "$birthyear"
echo "$gender"
else
echo "it failed"
fi
Есть несколько моментов, о которых нам нужно помнить
- используйте "" вместо ""
- используйте -a вместо &&
- ставьте пробел перед и после знака оператора, например [a=b], не используйте в качестве [a=b] в условии if
Следовательно, вышеуказанное решение сработало для меня !!!
Несколько раз, если вы случайно коснулись клавиатуры и убрали пробел.
if [ "$myvar" = "something"]; then
do something
fi
Вызовет это сообщение об ошибке. Обратите внимание на пробел перед ']'.
У меня была такая же проблема с моими сценариями. Но когда я сделал некоторые изменения, это сработало для меня. Я сделал это так:
export k=$(date "+%k");
if [ $k -ge 16 ]
then exit 0;
else
echo "good job for nothing";
fi;
таким образом я решил свою проблему. Надеюсь, что это поможет и вам.