7

Мне нужно перечислить все подкаталоги каталога, кроме тех, которые соответствуют любому из списка, заданного в качестве аргумента: «SUBDIR1, SUBDIR2, ..., SUBDIRN».

Я пришел с решением (из многих источников) использования ls с шаблоном glob. Чтобы проверить концепцию, я попытался в командной строке выполнить следующую последовательность действий:

DIR="/path/to/dirs"
EXCLUDELIST="subdir1,subdir2"
#transform in a glob pattern for excluding given subdirectories
EXCLUDE="!(${EXCLUDELIST//,/|})"
LIST=$(cd $DIR && ls -l -d $EXCLUDE | grep -E "(^d)" | awk '{print $9}')

Однако, когда я помещаю его в скрипт bash неизмененным, я получаю эту ошибку

ls: cannot access !(subdir1|subdir2): No such file or directory

Что я делаю неправильно, когда помещаю этот код в скрипт?

2 ответа2

7

Интерактивные и неинтерактивные оболочки bash не ведут себя одинаково. Одним из многих отличий является то, что параметр оболочки extglob включен по умолчанию для интерактивных оболочек (по крайней мере, в моей версии bash), но не для неинтерактивных.

Чтобы исправить ваш скрипт, включите extglob с помощью следующей команды:

shopt -s extglob
1

Деннис рассказал вам, почему ваш сценарий не работает, но я хотел бы предложить более простой (и более безопасный) способ сделать это. Парсинг ls почти всегда плохая идея, он может легко разбивать имена файлов пробелами, новыми строками или другими странными символами и не переносится в настройках LOCALE. Кроме того, ваша команда очень сложна, состоит из нескольких шагов. Почему бы не сделать все это в find?

DIR="/path/to/dirs"
EXCLUDELIST="subdir1,subdir2"
## Build the regular expression
EXCLUDE="${EXCLUDELIST//,/|.*}"
LIST=$(find "$DIR" -type d -regextype posix-awk -not -regex ".*$EXCLUDE.*")

Кстати, ваш скрипт потерпит неудачу в том виде, в каком вы его написали, потому что вы собираете глобус до cd -ing в $DIR поэтому он будет построен в соответствии с содержимым вашего текущего каталога.

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