Подбор только файлов в Bash

У меня проблемы с глобусами в Bash. Например:

echo *

Это распечатает все файлы и папки в текущем каталоге. например (файл1 файл2 папка1 папка2)

echo */

Это распечатает все папки с / после имени. например (папка1 / папка2 /)

Как я могу найти только файлы? например (файл1 файл2)

Я знаю, что это можно сделать с помощью синтаксического анализа ls, но также знаю, что это плохая идея. Я пробовал использовать расширенный blobbing, но тоже не смог заставить его работать.


person John P    schedule 23.12.2013    source источник


Ответы (4)


Без использования какой-либо внешней утилиты вы можете попробовать for loop с glob support:

for i in *; do [ -f "$i" ] && echo "$i"; done
person anubhava    schedule 23.12.2013
comment
Это похоже на то, о чем я думал. Большое тебе спасибо. Я не уверен, что полностью понимаю это. Выполняется ли итерация по глобу, а [-f $ i] проверяет, является ли это файлом? РЕДАКТИРОВАТЬ: только что проверил страницу руководства для тестирования. Спасибо еще раз! - person John P; 23.12.2013
comment
@JohnP, да. Вы также можете использовать [ ! -d "$i" ], чтобы проверить, что текущий элемент не является каталогом - тогда вы должны будете включать символические ссылки и другие типы файлов, но явно не каталоги. - person glenn jackman; 23.12.2013
comment
Да, точно! Цикл For выполняет итерацию каждой записи в текущем каталоге и [ -f "$i" ] проверяет, является ли эта запись обычным файлом. - person anubhava; 23.12.2013
comment
(!) test -f просто проверяет наличие простого (обычного) файла, не проверяя специальные файлы блоков (например, /dev/null), сокеты, символические ссылки [..]. - person Pavel; 06.09.2017

Я не знаю, сможете ли вы решить эту проблему с помощью globbing, но вы определенно можете решить эту проблему с помощью найти:

find . -type f -maxdepth 1
person Oliver Charlesworth    schedule 23.12.2013
comment
самый чистый, особенно используемый в args для какой-либо другой команды, например perl -pi -e 's/foo/bar/g' $(find . -maxdepth 1 -type f). О, мелочь: maxdepth должен быть первым, чтобы избежать предупреждения: вы указали параметр -maxdepth после аргумента без параметра -type (...) - person Pierre D; 25.08.2020

Вы можете делать то, что хотите в bash, вот так:

shopt -s extglob
echo !(*/)

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

Однако он не будет соответствовать символическим ссылкам, указывающим на каталоги.

Если вы хотите перебирать обычные файлы и ничего более, используйте find -maxdepth 1 -type f.

Безопасный и надежный способ его использования выглядит следующим образом:

find -maxdepth 1 -type f -print0 | while read -d $'\0' file; do
  printf "%s\n" "$file"
done
person Major Gnuisance    schedule 23.01.2016
comment
Ваше решение только для bash совпадает для меня с echo * - person rubystallion; 16.01.2019
comment
Также, чтобы активировать опцию extglob, вам нужно будет использовать shopt -s extglob, поскольку shopt extglob отображается только в том случае, если опция установлена. - person rubystallion; 27.05.2019
comment
Голосуя за безопасный способ использования find, обратите внимание, что решение extglob не работает, по крайней мере, не в bash 5. - person Paul Wagland; 27.01.2021

В этом сценарии я использую команду find. Мне просто нужно было использовать его, чтобы найти / заменить десятки экземпляров в заданном каталоге. Я уверен, что есть много других способов снять шкуру с этой кошки, но чистый for пример выше не является рекурсивным.

for file in $( find path/to/dir -type f -name '*.js' );
    do sed -ie 's#FIND#REPLACEMENT#g' "$file";
    done

person theruss    schedule 23.05.2021