Мой случай:
dir1
subdir1
FooFile
subdir2
dir2
subdir1
FooFile
subdir2
Итак, если я cd dir1
, я могу легко сделать что-то вроде find . | xargs grep "Foo"
, чтобы перечислить имена всех файлов, содержащих Foo
.
Проблема в том, что существует так много подкаталогов и файлов, что этот поиск занимает очень много времени. Я хотел бы рекурсивно зайти в каждый основной каталог, а затем перейти только к ОДНОМУ подкаталогу (subdir1) и затем выполнить grep.
Каков наилучший способ перечислить имена всех файлов, содержащих Foo
, из всех каталогов? Для каждого каталога с разными именами, subdir1
всегда находится на один уровень ниже dir1
, и всегда называется subdir1
точно.
Вы можете сделать это с помощью сценария, например,
#!/bin/sh
find . -type d | while IFS= read -r pathname
do
for name in "$pathname"/subdir1/*Foo*
do
[ -f "$name" ] && echo "$name"
done
done
с обычными оговорками о новых строках в именах путей. Протестировано с помощью этого дерева:
./dir2
./dir2/subdir1
./dir2/subdir1/FooFile
./dir2/subdir2
./subdir1
./subdir1/FooFile
./dir spacew
./dir spacew/subdir1
./dir spacew/subdir1/FooFile
./dir spacew/subdir2
./dir1
./dir1/subdir1
./dir1/subdir1/FooFile
созданный скрипт
./subdir1/FooFile
./dir2/subdir1/FooFile
./dir spacew/subdir1/FooFile
./dir1/subdir1/FooFile
Вопрос был неоднозначным относительно использования grep
(как написано, не было никакой разницы по сравнению с echo
, за исключением возможности использования регулярных выражений вместо подстановочных знаков оболочки). В качестве альтернативы вы можете напрямую использовать grep
:
#!/bin/sh
find . -type f -name '*Foo*' | grep -E 'subdir1/Foo[^/]*$' | while IFS= read -r pathname
do
echo "$pathname"
done
Дальнейшее чтение:
Если вы хотите посмотреть в ] и в всех (подкаталогах) с именем subdir1
, которые на один уровень ниже верхнего уровня, вы можете сделать
find */subdir1 …
. Если вы ищете файлы, у которых names содержат Foo
, вы можете сделать
find */subdir1 -type f -name "*Foo*" -print
Или вы можете сделать
find */subdir1 -type f -print | grep "Foo"
, но это будет включать каждый файл в каталоге
, имя которого включает строка Foo
,
например, dir42 / subdir1 / Foods_I_Like / pizza
и dir42 / subdir1 / Foods_I_Like / курица
.
Если вы ищете файлов, содержащих Foo
(т. Е., чье содержимое содержит Foo
), вы можете сделать
find */subdir1 -type f -print | xargs grep "Foo"
Примечания:
find
выглядит так: {{ 1}}
найти [ параметры ] [ начальная точка ... ] [ выражение ]т. Е. Вы можете вызвать
find
один раз в нескольких начальных точках; как в:
найти dir1 / subdir1 dir2 / subdir1 [ выражение ]
Foo
,
не включайте -тип f
в соответствующих командах. . "* Foo *"
и не должны цитировать * / subdir1
.
Цитирование "Foo"
необязательно -
это не повредит, но вам не нужно цитировать
слова, не содержащие специальных символы. -print
, поскольку это действие по умолчанию. что насчет
grep "foo" */subdir1/* */subdir1/.*
? (исходя из вашего текущего вопроса, это кажется подходящим вариантом. если только не существует так много поддиректорий "subdir1", что оболочка не может предоставить весь список для grep.
Вы можете добавить -q и проверить, выйдет ли он с 0, если вы просто хотите посмотреть, появляется ли "foo" в файле
Вы также можете сделать рекурсивный grep, а затем отбросить то, что вам не нужно (тяжело для i/o, но просто) :
grep -r "foo" . | grep "^\./[^/][^/]*/subdir1/[^/][^/]*:"
(См. комментарии ниже: здесь, даже если имя содержит ":", это будет работать, так как вы нашли имя файла в поддиректории subdir1, и этот файл содержит foo. Однако он может пропустить файл, содержащий новую строку в имени, так как во втором grep он не увидит первое имя "./firstleveldir/", поэтому второй grep отклонит его...)
.