Я пишу сценарий Борна и хочу выбрать файлы, соответствующие определенным регулярным выражениям. Я делаю это с помощью тестовой структуры if, и она определяет файл, заканчивающийся на ".o". Однако, когда в каталоге есть два файла, которые я ищу и заканчивающиеся на «.o», я получаю следующую ошибку: «expr: syntax error». Как такое могло быть?

    if test "`expr \"$file\" : ${SPECIFIED_DIRECTORY}/*.o`" != "0"; then
       do something
    fi
1
Iman Askur 12 Мар 2014 в 00:38
Подумай об этом. Регулярное выражение *.o раскрывается перед запуском expr, поэтому ему передается более одного аргумента с правой стороны.
 – 
Charles Duffy
12 Мар 2014 в 00:42
Кстати, в современных системах /bin/sh — это POSIX sh (что на самом деле ближе к ksh88), а не Bourne (который буквально представляет собой оболочку из 70-х). Вы уверены, что действительно нацелились на Борна?
 – 
Charles Duffy
12 Мар 2014 в 00:43

3 ответа

Лучший ответ

Тест на регулярное выражение почти наверняка не подходит для этой работы, но давайте предположим, что specified_directory (строчные буквы по соглашению, чтобы избежать конфликтов с переменными среды и встроенными функциями) содержал регулярное выражение для соответствия имени каталога, а не буквальным именем, и поэтому был правильным инструментом. Если бы это было так, вы бы хотели написать ...

if expr "$file" : "$specified_directory"/'.*[.]o' >/dev/null; then
  ...
fi

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

Если вы не экранируете . (в данном случае, сделав его классом символов, [.]), он имеет свое обычное значение регулярного выражения - совпадение ровно одного символа. Точно так же .* - это способ сопоставить ноль или более любых символов в регулярном выражении, а не только * (который является синтаксисом fnmatch).

0
Charles Duffy 12 Мар 2014 в 00:45
Спасибо, Чарльз! Недостаток опыта делает меня склонным к неверным решениям и непониманию. Я ценю, что вы указали мне правильное направление.
 – 
Iman Askur
12 Мар 2014 в 00:59

Этот подход работает с любой оболочкой POSIX и не вызывает никаких инструментов, недоступных встроенным в оболочку, что делает его эффективным во время выполнения.

contains_any_files() {
  set -- "$1"/*
  [ "$#" -gt 0 ] && [ -f "$1" ]
}

if contains_any_files "$dir"; then
   ...
fi
0
Charles Duffy 12 Мар 2014 в 01:06

Если я правильно понял, если в каталоге есть файлы .o, то сделайте что-нибудь:

if find "$dir"/*.o >/dev/null 2>&1; then
    # do something
fi

Команда find завершится успешно, только если есть какие-либо совпадающие файлы. В противном случае он завершится с ошибкой, и блок then не будет выполнен. >/dev/null 2>&1 скрывает stdout и stderr.

0
janos 17 Мар 2014 в 15:05
&> не соответствует POSIX. Вопрос явно требует /bin/sh.
 – 
Charles Duffy
12 Мар 2014 в 01:00
Я заменил ls на find. Теперь это имеет больше смысла. Я не знаю, что вообще побудило меня использовать ls...
 – 
janos
12 Мар 2014 в 01:13
Ну, как вы там пишете, оболочка расширяет глобус еще до того, как поиск запущен, и просто передает список уже расширенных имен (если они существуют) или несуществующий глобус (если нет) . Это работает, но я не уверен, что использование find стоит усилий.
 – 
Charles Duffy
12 Мар 2014 в 01:57