Шаблон Bash для соответствия всем файлам, но каталоги

В bash, как мне указать шаблон, который соответствует всем, кроме подкаталогов в текущем каталоге. Учитывая, что шаблон */ соответствует всем подкаталогам, я попробовал (с включенным extglob):

 $ echo !(*/) 

Но это не сработало.

 find . -maxdepth 1 ! -type d 

Детали:

  • -maxdepth 1 ограничивает поиск текущим каталогом

  • ! -type d ! -type d исключает каталоги

Причина */ соответствует каталогам в том, что final / ограничивает соответствие каталогам. Этот эффект срабатывает только тогда, когда / после шаблона, вы не можете использовать / внутри круглых скобок в !(*/) . В bash нет встроенной функции, чтобы делать то, что вы хотите.

Вы можете сделать цикл над всеми файлами и построить массив.

 non_directories=() for x in *; do [ -d "$x" ] || non_directories+=("$x") done somecommand "${non_directories[@]}" 

Вы также можете использовать find , если хотите выполнить команду над всеми файлами. Если ваша реализация поиска поддерживает его (GNU, BSD, BusyBox), используйте -mindepth и -maxdepth чтобы перечислять только записи в текущих каталогах (с ./-preended). Используйте ! -name '.*' ! -name '.*' чтобы опустить файлы точек (если вы действительно хотите их опустить).

 find . -mindepth 1 -maxdepth 1 ! -type d -exec somecommand {} + 

Если вы можете предполагать только POSIX, используйте -prune чтобы избежать рекурсии.

 find . -name . -o -type d -prune -o -exec somecommand {} + 

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

В zsh вы можете использовать квалификаторы glob : *(^/) или *(.) Для соответствия только обычным файлам.

Вид длинной ветры, но:

 for f in *; do if [ ! -d "$f" ]; then echo "$f"; fi; done 

-d – это оператор проверки файлов, проверяющий, является ли аргумент каталогом.

Вышеупомянутое можно также сократить до

 for f in *; do [ ! -d "$f" ] && echo "$f"; done 

Мое предложение:

 GLOBIGNORE=$(echo */) # create list of directories with globbing GLOBIGNORE=${GLOBIGNORE//:/\\:} # escape possible ":" with "\" to allow # the separator ":" in directory names GLOBIGNORE=${GLOBIGNORE//\/ /:} # replace "/ " with separator ":" GLOBIGNORE=${GLOBIGNORE%/} # remove trailing "/" ls -ld * 

Результат: нет каталогов

Вернуться к умолчанию с unset GLOBIGNORE

Я не уверен, какой из двух вариантов вы хотите достичь – bash globing, который исключает на основе атрибутов файловой системы или способ отображения только файлов в каталоге?

Если первый, я не уверен, что это возможно. Globing просто расширяется, а имена файлов являются базой в любом каталоге – bash не различает имя файла или имя dirname на своем собственном.

Если второе – у вас уже есть 2 ответа, другой – ls:

 ls -dF * | grep -v "/$"