2

Попытка заставить переменную встретить строку текста, которая варьируется по длине. Часть строки, которая имеет значение, является первой парой символов.

var1=hello  
if [ $var1 == hello ]; then  
    echo success  
fi

Или же

var1=hello  
if [ $var1 == h*o ]; then  
    echo success  
fi

Выходы: успех

Но так как меня волнуют первые 3 символа или около того, это звучит логично, но не работает:

var1=hello  
if [ $var1 == hel* ]; then  
    echo success  
fi

Выводы: -bash: [: слишком много аргументов

Так как я забочусь только о первых двух персонажах, я могу сделать:

var1=hello 
if [ ${var1:0:3} == hel ]; then 
    echo success  
fi

Это сработало бы, но я ищу объяснение, почему я получаю эту ошибку и возможное лучшее письменное решение.

4 ответа4

3

Когда вы используете * в таком if , он будет расширять имя файла. Итак, в первом случае, h*o вероятно, соответствует файлу в вашем текущем каталоге, и поэтому тест пройден.

hel* соответствует нескольким файлам, и поэтому стало слишком много аргументов для команды if .

Попробуйте использовать if [[ $var1 == hel* ]]; then

Двойные скобки превращают тест в регулярное выражение, и подстановочный знак * будет работать так, как вы ожидаете.

1

[ * - это обычная команда, похожая на grep , find или cat . Вы должны быть в состоянии найти его в /bin . Поскольку это отдельная программа, оболочка выполнит свой обычный набор расширений перед передачей [ своих аргументов.

Как уже упоминалось, поскольку вы используете * в своих тестах, вы получаете глобальные расширения. Обратите внимание, что даже если вы используете кавычки, такие как 'hel*' , это, вероятно, не сработает, как вы надеетесь, потому что [ не поддерживает шаблоны. В случае h*o работает это, скорее всего, из-за наличия файла с именем hello в вашем текущем каталоге, а также отсутствия других файлов, соответствующих этому шаблону. Если он работает без файла hello , у вас может быть странная реализация, и ваш сценарий, скорее всего, выйдет из строя на других системах.

В зависимости от ваших потребностей, есть несколько вариантов. У Bash, Zsh и некоторых других оболочек есть [[ встроенный. Поскольку он встроенный, он может обрабатывать свои аргументы особым образом, в том числе избегать глобальных расширений. Кроме того, он может сделать сопоставление с образцом. Пытаться

var1=hello  
if [[ "$var1" = hel* ]]; then  
    echo success  
fi

Также обратите внимание на отсутствие кавычек вокруг шаблона. Без кавычек hel* трактуется как шаблон [[ , с кавычками (одинарными или двойными), "hel*" трактуется буквально.

Если вам нужна более широкая совместимость, например, для оболочек без [[ , вы можете использовать grep:

var1=hello
if echo "$var1" | grep -qe 'hel.*' ; then
    echo success
fi

Нет [ или [[ необходимо здесь, но есть кавычки вокруг 'hel.*' .

* У некоторых оболочек действительно есть [ встроенный, но это для эффективности. Он по-прежнему должен вести себя идентично отдельному исполняемому файлу, в том числе подвергать свои аргументы обычному "искалечению" оболочки.

1

У меня есть трюк, который я использую для взлома регулярных выражений без использования встроенного регулярного выражения bash. Пример для # 2. Это работает так, как grep не возвращает выходных данных (то есть несуществующей строки), если она ничего не соответствует. Итак, есть два теста: -z означает "пустая строка" и -n означает "имеет данные".

if [ -n "`echo $var1 | grep -e 'h.*o'`" ] ; then
  echo 'water found'
fi
0

Как насчет этого ?

if [["$ var1" == "hel" *]]

Дайте подстановочный знак за пределами кавычек, делая сравнение строк.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .