Bash: проверьте, возвращает ли команда определенное значение

Я пытаюсь написать скрипт .sh, где в определенный момент он проверяет, есть ли в текущем каталоге один или несколько файлов, соответствующих *\_??\_??\_64kbs.mp3

ИЛИ, используя регулярное выражение ^.*\_..\_..\_64kbs\.mp3$

Это одна попытка команды:

if [ 'ls *_??_??_64kbs.mp3 2>/dev/null | wc -l ' == 0 ];
then echo "nothing";
else echo "something";
fi

я знаю это

'ls *_??_??_64kbs.mp3 2>/dev/null | wc -l'

в этом случае возвращает на терминал только число 9, потому что есть 9 совпадений. Если я удалю первый '?', он вернет 0, как и должно быть, потому что нет имен файлов, соответствующих этому выражению. Но вывод приведенного выше выражения if всегда «что-то».

РЕДАКТИРОВАТЬ: кто-то попросил полное имя файла образца для того, что я пытаюсь сопоставить. Вот один:

George-1983_1A_01_64kbs.mp3

person Matthew Jendrasiak    schedule 28.03.2017    source источник
comment
Можете ли вы привести полное имя файла образца в качестве примера?   -  person Inian    schedule 28.03.2017
comment
посмотри на $?   -  person Aif    schedule 28.03.2017
comment
Просто добавил к вопросу пример имени файла, Inian.   -  person Matthew Jendrasiak    schedule 28.03.2017
comment
Айф, я не понимаю твоего предложения.   -  person Matthew Jendrasiak    schedule 28.03.2017
comment
вы проверяете, равна ли строка 'ls ....' 0, чего никогда не бывает.   -  person mata    schedule 28.03.2017
comment
Ты прав. Раньше я пытался обернуть команду $('command') и, похоже, это вызывало ошибки, но теперь все работает нормально. Возможно, в то время я не включил «2›/dev/null» в команду, и это вызывало проблему.   -  person Matthew Jendrasiak    schedule 28.03.2017
comment
@MatthewJendrasiak: Обратитесь к моему ответу, используя совпадения glob и regex, что здесь является правильным подходом.   -  person Inian    schedule 28.03.2017
comment
Не используйте ls для поиска файлов. Вместо этого используйте find.   -  person ceving    schedule 28.03.2017
comment
Также взгляните на этот ответ: stackoverflow.com/a/6364244/5092659   -  person Samuel Kirschner    schedule 28.03.2017
comment
@Aif Это антипаттерн, скрипты очень редко должны проверять $? напрямую. Все конструкции управления потоком проверяют эту переменную за кулисами, поэтому вам не нужно этого делать. Так что cmd; if [ $? == 0 ]; then... лучше писать if cmd; then...   -  person tripleee    schedule 28.03.2017


Ответы (2)


Вы явно путаете glob с совпадением regex, * — это чистая конструкция glob, которую можно использовать в цикле, как показано ниже.

fileNamePattern="*_??_??_64kbs.mp3"
for file in *.mp3; do
    [[ $file == $fileNamePattern ]] && echo "$file matches"
done 

Значение ? и * отличается при использовании в контексте regex, где мы используем .* для сопоставления с частью и .{} для представления любого символа, появление которого может быть продиктовано значением внутри {}, например,

fileNameRegex=".*_.{2}_.{2}_64kbs.mp3"
for file in *.mp3; do
    [[ $file =~ $fileNameRegex ]] && echo "$file matches"
done

~ – это оператор регулярного выражения bash (поддерживается, начиная с bash версии 4.0), который требуется для сопоставления с регулярным выражением, а не с glob.

person Inian    schedule 28.03.2017
comment
Спасибо за ответ, и это работает, но я явно не путал glob с регулярным выражением. Вы можете видеть, что в начале моего вопроса я предложил регулярное выражение, эквивалентное глобусу, который я использовал в примере. Это то же самое, что и ваше, за исключением того, что я явно пишу .. вместо .{2}, и я предваряю его ^ и заканчиваю его $. - person Matthew Jendrasiak; 28.03.2017
comment
@MatthewJendrasiak: Ценю это! Хотя при использовании подходов glob и regex возникла некоторая путаница. Если это решило вашу проблему, не забудьте проголосовать и принять его, чтобы он был полезен для будущих читателей. - person Inian; 28.03.2017

Я нашел решение, которое, кажется, работает. Заключите команду в $() вместо кавычек.

if [ $(ls *_??_??_64kbs.mp3 2>/dev/null | wc -l) == 0 ];
then echo "nothing";
else echo "something";
fi

Я пробовал что-то подобное ранее, и это не сработало, но, должно быть, была синтаксическая ошибка. В данном случае это работает.

person Matthew Jendrasiak    schedule 28.03.2017
comment
Это явно неправильный путь. Разбор вывода ls обычно не рекомендуется, см. Почему не следует выполнять синтаксический анализ вывод ls - person Inian; 28.03.2017
comment
чтобы пролить свет на возможную синтаксическую ошибку, кажется, вы пытались 'ls ...' (буквальная строка ls ...) $('ls ...') (вывод команды с именем ls ...., файлы и, следовательно, команды могут содержать пробелы) никогда $(ls ...) или `ls ...` (оба работают). - person Samuel Kirschner; 28.03.2017
comment
Кроме того, конвейер к wc -l является очень распространенным антипаттерном. См. iki.fi/era/unix/award.html#wc. - person tripleee; 28.03.2017