2016-02-07 3 views
1

Я попытался установить условное выражение в сценарии bash, но я столкнулся с необычной ошибкой; Баш жалуется на слишком много аргументов, но все кажется правильным для меня:Восклицательный знак и слишком много аргументов

[ "${foo:0:1}" = '!' -o "$foo" = '*' ] 

Проще говоря, тест должен добиться успеха, если $foo либо звездочка, или начинается с восклицательным знаком.

Однако, когда $foo начинается с восклицательным знаком, я получаю следующее сообщение об ошибке в Баш:

bash: [: too many arguments 

Странная вещь является то, что она отлично работает, если я опустить второе условие так:

[ "${foo:0:1}" = '!' ] 

Итак, кажется, что оценка восклицательного знака как-то мешает логике или условию, может ли кто-нибудь объяснить, что здесь происходит, и как наилучшим образом будет работать вокруг него?

Это, кажется, не имеет значения, что я тестирую для, например:

[ "${foo:0:1}" = 'z' -o "$foo" = '*' ] 

Будет ли еще потерпеть неудачу, если $foo начинается с восклицательным знаком. Это меня беспокоит, так как у меня есть множество сценариев, которые проверяют символы таким же образом, что, предположительно, неожиданно может произойти неожиданно, если значение содержит восклицательный знак, поэтому я мог бы найти подходящее обходное решение для этого.

+0

Я предполагаю, что вы используете скрипт с 'sh' вместо' bash', что означает, что вы не можете использовать расширения Bash, такие как '-o'. – tripleee

ответ

2

Если вы не нацелены на совместимость с POSIX, предпочитайте [[ более [ при использовании bash. Это безопаснее, проще и мощнее.

Например, вы могли бы использовать regular expressions:

[[ $foo =~ '^(!|\*$)' ]] 

И [[ конструкция поддерживает || и &&, которые вы должны предпочитать по -o и -a:

[[ "${foo:0:1}" = '!' || "$foo" = '*' ]] 

Раскрывание происходит прежде, чем переменная расширение, поэтому foo, содержащий !, не должно вызывать проблем из-за расширения истории.Что могло случиться, что [ видит ! как оператор отрицания:

$ help [ 
[: [ arg... ] 
    This is a synonym for the "test" builtin, but the last 
    argument must be a literal `]', to match the opening `['. 
[[ ... ]]: [[ expression ]] 
    Returns a status of 0 or 1 depending on the evaluation of the conditional 
    expression EXPRESSION. Expressions are composed of the same primaries used 
    by the `test' builtin, and may be combined using the following operators 

     (EXPRESSION) Returns the value of EXPRESSION 
     ! EXPRESSION True if EXPRESSION is false; else false 

полную команду (скажем, если foo='!abcd') становится:

[ '!' = '!' -o '!abcd' = '*' ] 

Какой будет обработан:

NOT(= '!' -o '!abcd' = '*') 

И если вы попробуете внутреннее выражение, вы получите ту же ошибку:

$ [ = '!' -o a = a ] 
sh: [: too many arguments 

Обычным решением является префиксом строки с другим персонажем:

Посмотрите .

+0

Спасибо muru и @joao за ваши ответы! Я собираюсь выбрать этот вариант, поскольку он содержит варианты как для багизмов, так и для соответствия posix, и в этом случае я буду выбирать решение (ы) bash. – Haravikk

3

Вы можете обойти его, разделив ваше выражение:

[ "${foo:0:1}" = '!' ] || [ "$foo" = '*' ] 

Так Bash не извратить, что вы имеете в виду с '!' - если строка или оператора not.

+0

Это похоже на легкую замену для многочисленных сценариев OP. –

+1

Да, но, пожалуйста, оставьте '=' как таковой. '==' вместо '=' in '[' не является стандартным и не дает никакой пользы. – jilles

+0

@jilles вы правы, '=' лучше с одним '['. Изменено. –

Смежные вопросы