Здесь мы исключаем dir1 , dir2 и dir3 , так как в findвыражениях это действие, которое действует по критериям -path dir1 -o -path dir2 -o -path dir3(если dir1 или dir2 или dir3 ), а также с type -d.
Хм. Это также не работает для меня, так как будет включать игнорируемый каталог "./misc" в выводе.
Theuni 12.12.12
84
@ Theuni Это, вероятно, не сработало для вас, потому что вы не добавили -print(или любое другое действие) явно после -name. В этом случае обе «стороны» -oпечати заканчиваются, тогда как при использовании -printпечатается только эта сторона.
Даниэль С. Собрал
4
С man-страницы: Because -delete implies -depth, you cannot usefully use -prune and -delete together.Итак, как мне выполнить удаление с помощью find, если я хочу исключить определенные каталоги из удаления?
Янис Элмерис
15
Для того, чтобы удалить весь каталог непосредственно от использования результатов: find . -not -path "./.git*". Использование ./dir*вместо ./dir/*удаляет каталог, а также содержимое из вывода.
micahblu
64
Этот вопрос и путаница в ответах свидетельствуют о том, насколько плохо пользовательский интерфейс find соответствует тому, что нужно людям.
Йоханнес Оверманн
1932
Если у -pruneвас не работает, это будет:
find -name "*.js"-not -path "./directory/*"
Предостережение: требует прохождения всех нежелательных каталогов.
Один из комментариев в принятом ответе указывает на проблему. -pruneне исключает сам каталог, он исключает его содержимое, что означает, что вы получите нежелательную строку в выводе с исключенным каталогом.
GetFree
96
Отличный ответ. Я бы добавил к этому, что вы можете исключить каталог на ЛЮБОМ уровне, изменив первый .на *. таким образом find -name "*.js" -not -path "*/omitme/*", файлы любого каталога с именем «omitme» будут опущены на любом уровне глубины.
DeeDee
83
Тем не менее, он по-прежнему пересекает весь нежелательный каталог. Я добавляю свой собственный ответ. :-)
Даниэль С. Собрал,
18
Обратите внимание, однако, что опция сокращения не работает, только если вы не используете -printявно.
Даниэль С. Собрал,
39
Было бы лучше сказать «Это альтернатива использованию -prune». Ответы о том, что -prune явно не ошибочны, они просто не такие, как вы.
Джимбо
459
Я считаю, что следующее легче рассуждать, чем другие предлагаемые решения:
Важное примечание: пути, которые вы вводите после, -pathдолжны точно соответствовать тому, что findбудет напечатано без исключения. Если это предложение Вас смущает только убедитесь , что используются полные пути через из всей команды , как это: . Смотрите примечание [1], если вы хотите лучшего понимания.find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...
Внутри \(и \)это выражение, которое будет точно соответствоватьbuild/external (см. Важное примечание выше), и, в случае успеха, позволит избежать обхода чего-либо ниже . Затем он группируется как одно выражение с экранированными скобками и с префиксом, -notкоторый заставит findпропустить все, что соответствует этому выражению.
Кто-то может спросить, не добавит ли при добавлении -notвсе остальные файлы при -pruneповторном появлении, и ответ - нет. То , как -pruneработает то , что все , что, как только это будет достигнуто, то файлы ниже этого каталога постоянно игнорируются.
Это происходит из реального случая использования, когда мне нужно было вызвать yui-compressor для некоторых файлов, сгенерированных wintersmith, но исключить другие файлы, которые необходимо отправить как есть.
Примечание [1] : Если вы хотите исключить, /tmp/foo/barи вы запускаете поиск, как это " find /tmp \(...", то вы должны указать -path /tmp/foo/bar. Если, с другой стороны, вы запускаете find, как это, cd /tmp; find . \(...вы должны указать -path ./foo/bar.
Отличный ответ, спасибо. Это работает и является масштабируемым (читаемым) для нескольких исключений. Вы джентльмены и ученый, сэр. Спасибо за пример для нескольких исключений
Freedom_Ben
7
Это не работает, если я хочу использовать ключ -delete:find . -not \( -path ./CVS -prune \) -type f -mtime +100 -delete find: The -delete action atomatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
Jānis Elmeris
17
@Janis Вы можете использовать -exec rm -rf {} \;вместо -delete.
Даниэль С. Собрал
11
Изучив вывод find, это действительно очевидно, но это сбило меня с толку. Если вы ищете в текущем каталоге (указав в .качестве пути поиска или не указывая один на всех), то вы , скорее всего , хотите , чтобы ваш шаблон после того, как -pathначать с ./, например: find -not \( -path ./.git -prune \) -type f.
Зантье
7
Более точный (и POSIX-совместимый) вариант этого метода: find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)следуют любые условия, которые должны соответствовать тому, что вы ищете.
Уолф
219
Здесь явно есть некоторая путаница относительно того, каким должен быть предпочтительный синтаксис для пропуска каталога.
Мнение GNU
To ignore a directory and the files under it, use -prune
-pruneостанавливается findот спуска в каталог. Простое указание -not -pathбудет все равно попадать в пропущенный каталог, но -not -pathбудет ложным, когда findпроверяется каждый файл.
Проблемы с -prune
-prune делает то, для чего он предназначен, но все же есть некоторые вещи, о которых вы должны позаботиться, используя его.
find печатает сокращенный каталог.
TRUE Это намеченное поведение, оно просто не сходит в него. Чтобы вообще не печатать каталог, используйте синтаксис, который логически его опускает.
-pruneработает только с -printи без других действий.
НЕ ПРАВДА . -pruneработает с любым действием, кроме -delete. Почему это не работает с удалением? Для -deleteработы find необходимо пройти по каталогу в порядке DFS, так -deleteкак сначала будут удалены листья, затем родители листьев и т. Д. Но для определения -pruneсмысла findнеобходимо обратиться к каталогу и прекратить его нисходящее движение, что явно не имеет смысла с -depthили -deleteна.
Представление
Я установил простой тест из трех самых популярных ответов на этот вопрос (заменил -printна, -exec bash -c 'echo $0' {} \;чтобы показать другой пример действия). Результаты ниже
----------------------------------------------# of files/dirs in level one directories.performance_test/prune_me 702702.performance_test/other 2----------------------------------------------> find ".performance_test"-path ".performance_test/prune_me"-prune -o -exec bash -c 'echo "$0"'{} \;
.performance_test
.performance_test/other
.performance_test/other/foo
[# of files]3[Runtime(ns)]23513814> find ".performance_test"-not \( -path ".performance_test/prune_me"-prune \) -exec bash -c 'echo "$0"'{} \;
.performance_test
.performance_test/other
.performance_test/other/foo
[# of files]3[Runtime(ns)]10670141> find ".performance_test"-not -path ".performance_test/prune_me*"-exec bash -c 'echo "$0"'{} \;
.performance_test
.performance_test/other
.performance_test/other/foo
[# of files]3[Runtime(ns)]864843145
Вывод
Оба синтаксис f10bit в и синтаксис Daniel C. Собрал в взяли 10-25ms бежать в среднем. Синтаксис GetFree , который не используется -prune, занял 865 мс. Итак, да, это довольно экстремальный пример, но если вы заботитесь о времени выполнения и делаете что-то дистанционно интенсивное, вы должны использовать -prune.
Обратите внимание, что синтаксис Даниэля С. Собрала был лучшим из двух -pruneсинтаксисов; но я сильно подозреваю, что это результат некоторого кеширования, так как переключение порядка, в котором выполнялись два процесса, приводило к противоположному результату, в то время как версия без обрезки всегда была самой медленной.
Спасибо за очень хороший анализ. Что касается «Я сильно подозреваю, что это результат некоторого кеширования», вы можете запустить эту команду: sudo sh -c «free && sync && echo 3> / proc / sys / vm / drop_caches && free», чтобы очистить кеш (см. Unix. stackexchange.com/questions/87908/… ).
ndemou
После нескольких тестов на этих двух -pruneя могу сказать, что редко есть какая-либо разница. Имейте в виду, что какая команда запускается в первую очередь выиграет от производительности процессора, позднее снижение производительности процессора> приведет к незначительному замедлению (я чистил кэш перед каждой командой в соответствии с предложением @ndemou)
Huy.PhamNhu
Попробуйте переключить число среди name1() name2() name3()в тестовом скрипте @BroSlow выше, чтобы изменить порядок выполнения, чтобы получить визуальное представление о том, что я сказал. В реальной жизни это незаметно между этими двумя, хотя.
Huy.PhamNhu
Аплодисменты. Спасибо за этот качественный ответ.
Стефан
Вы не должны быть -о, что означает или. так что вы обрезаете первый шаг, а потом забываете об этом в следующем.
ммм
97
Это единственный, который работал на меня.
find /-name MyFile!-path '*/Directory/*'
Поиск "MyFile", исключая "Каталог". Сделайте акцент на звезды *.
Этот работал для меня, другие (которые используют -prune) - нет.
Андрон
7
Медленно в больших результатах, но полезно в меньших наборах. Но как исключить несколько каталогов, используя grep? Конечно так: find . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3но может быть какой-то один способ grep.
Тимо Кяхконен
6
Если вы хотите , чтобы выполнить несколько отбирает , то вы бы лучше писать его в виде регулярных выражений: egrep -v '(dir1|dir2|dir3)'. Однако в этом конкретном примере лучше было бы исключить каталоги внутри findсебя.
Лоуренс
1
да, вам не нужны круглые скобки, и было бы лучше использовать ^, чтобы убедиться, что он совпадает с именем каталога в начале строки, например: find. имя * .js | egrep -v "^ \ ./ excludedir1 | ^ \ ./ excludedir2"
София
41
Я предпочитаю -notобозначения ... это более читабельно:
Это единственное решение «найти», которое сработало для меня. Каталоги, которые я хотел исключить, НЕ находятся сразу под текущим рабочим каталогом.
Ламбарт
5
Однако добавление -printв конец может улучшить результаты. find . -type d -name .hg -prune -o -name dataигнорирует содержимое (нескольких) .hgкаталогов, но перечисляет .hgсами каталоги. При этом -printон только перечислил каталоги данных, которые я искал.
Ламбарт
19
-pruneопределенно работает и является лучшим ответом, потому что он предотвращает спуск в каталог, который вы хотите исключить. -not -pathкоторый все еще ищет исключенный каталог, он просто не печатает результат, что может быть проблемой, если исключенный каталог является подключенным сетевым томом или у вас нет разрешений.
Сложность заключается в том, что findочень важно определить порядок аргументов, поэтому, если вы не получите их правильно, ваша команда может не сработать. Порядок аргументов обычно таков:
find {path}{options}{action}
{path}: Сначала поместите все аргументы, связанные с путем, например . -path './dir1' -prune -o
{options}: У меня больше всего успехов, когда я ставлю -name, -iname, etcпоследний вариант в этой группе. Например-type f -iname '*.js'
{action}: Вы хотите добавить -printпри использовании-prune
Вот рабочий пример:
# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js
# search for *.js, exclude dir1
find .-path './dir1'-prune -o -type f -iname '*.js'-print
# search for *.js, exclude dir1 and dir2
find . \( -path './dir1'-o -path './dir2' \) -prune -o -type f -iname '*.js'-print
Я попробовал это, и это все еще спускается в каталоги, таким образом, скорость определенно не улучшена.
Br.Bill
10
Подход -path -prune также работает с подстановочными знаками в пути. Вот оператор find, который найдет каталоги для сервера git, обслуживающего несколько репозиториев git, оставив внутренние каталоги git:
Есть много хороших ответов, мне просто потребовалось некоторое время, чтобы понять, для чего предназначен каждый элемент команды и какая логика стоит за ним.
find .-path ./misc -prune -o -name '*.txt'-print
find начнет поиск файлов и каталогов в текущем каталоге, отсюда и find ..
-oВариант обозначает логическое ИЛИ и разделяет две части команды:
[-path ./misc -prune ] OR [-name '*.txt'-print ]
Любой каталог или файл, который не является каталогом ./misc, не пройдет первый тест -path ./misc. Но они будут проверены против второго выражения. Если их имя соответствует шаблону, который *.txtони получают, из-за -printопции.
Когда find достигает каталога ./misc, этот каталог удовлетворяет только первому выражению. Так что -pruneопция будет применена к нему. Он сообщает команде find не исследовать этот каталог. Таким образом, любой файл или каталог в ./misc даже не будет проверен командой find, не будет проверен на соответствие второй части выражения и не будет напечатан.
У каждого есть решение, но твое объяснило это лучше всего. Я был непреклонен, чтобы сначала использовалось -name, а не -path. Ваше объяснение было достаточно, чтобы прийти к тому, что я хотел. найти . -name "* .txt" -print -o -path ./misc -prune
Вендетта V
7
Для рабочего решения (проверено на Ubuntu 12.04 (Precise Pangolin)) ...
find !-path "dir1"-iname "*.mp3"
будет искать файлы MP3 в текущей папке и подпапках, за исключением подпапки dir1.
Не работает для меня Ни один из вышеперечисленных ответов. Красная шляпа.
Тарпа
6
Хорошая уловка для того, чтобы избежать печати сокращенных каталогов - использовать -print(работает -execтакже) после правой стороны -orпосле -prune. Например, ...
find .-path "*/.*"-prune -or -iname "*.j2"
напечатает путь ко всем файлам под текущим каталогом с расширением `.j2", пропуская все скрытые каталоги. Аккуратно. Но он также напечатает на распечатке полный путь каждого каталога, который пропускается, как отмечено выше. Однако, следующее не ...
find .-path "*/.*"-prune -or -iname "*.j2"-print
потому что по логике есть скрытый -andпосле -inameоператора и перед -принтом. Это связывает его с правой частью -orпредложения из-за логического порядка операций и ассоциативности. Но в документах говорится, что есть скрытое, -printесли оно (или любой из его двоюродных братьев ... -print0и т. Д.) Не указано. Так почему же не левая часть -orпечати? Очевидно (и я не понял этого после моего первого прочтения страницы руководства), это верно, если там нет -print-ЛИ -execВСЕГДА, и в этом случае -print логически разбрасывается так, что все печатается. Если даже ОДИНprint операции стиля, выраженной в каком-либо предложении, все эти скрытые логические операции исчезают, и вы получаете только то, что вы уточнить. Честно говоря, я бы предпочел это наоборот, но потомfind только описательных операторов, по-видимому, ничего не сделало бы, так что я думаю, что это имеет смысл, как есть. Как упомянуто выше, все это также работает -exec, поэтому следующее дает полный ls -laсписок для каждого файла с желаемым расширением, но не перечисляет первый уровень каждого скрытого каталога, ...
find .-path "*/.*"-prune -or -iname "*.j2"-exec ls -la --{}+
Для меня (и других в этом потоке) findсинтаксис довольно быстро становится довольно барочным, поэтому я всегда добавляю парены, чтобы УВЕРЕН, что я знаю, что с чем связано, поэтому я обычно создаю макрос для типа-способности и формирую все такие операторы как. ..
find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ...[-exec or -print] \)
Трудно ошибиться, настроив мир на две части. Я надеюсь, что это поможет, хотя вряд ли кто-то зачитает 30-й ответ и проголосует за него, но можно надеяться. :-)
Решение grep - единственное, которое исключает все каталоги с одинаковыми именами. При попытке исключить "node_modules", что весьма полезно.
bmacnaughton
3
@bmacnaughton - не правда! Я пришел сюда специально, чтобы исключить "node_modules", и после прочтения многих прекрасных ответов я остановился на find . -type f -print -o -path "*/node_modules" -prune... с использованием подстановочного знака, который пропускает "node_modules" на любом уровне; использование -printпервого варианта -type f -printприводит к печати только этой части, поэтому сами каталоги "node_modules" не перечислены. (он также может быть отменено: find . -path "*/node_modules" -prune -o -type f -print)
Стивен P
что * / делает там. Какой именно файл вы хотите исключить. Используете ли вы его в качестве подстановочного знака?
Siju V
1
@StephenP, спасибо за указание на это; Я узнал разницу между использованием ./node_modulesи */node_modulesот него. Для моего случая, когда node_modulesсуществует только в каталоге, в котором я начинаю поиск (и в этом node_modulesкаталоге), я могу использовать, find . -type f -print -o -path "./node_modules" -prune потому что не будет node_modulesкаталога в любом другом каталоге.
bmacnaughton
1
@SijuV - в каталоге, где я искал, был node_modulesподкаталог, но были также подкаталоги, которые имели свои собственные node_modules ... используя ./node_modulesсовпадения только с подкаталогом node_modulesв текущем каталоге .и удаляя его; используя */node_modulesспички и чернослив каталог на любой глубине, так *как Глоб соответствует любому ведущему префиксу пути, например ./test5/main/node_modules, не только ./приставка. Это *подстановочный знак, но не как регулярное выражение.
Не могу заставить это работать. find ~/Projects -name '*.js' -\! -name 'node_modules' -pruneдо сих пор node_modules
обнаруживает
1
@mpen, из stackoverflow.com/questions/4210042/… я узнал, что синтаксис, который вы хотите, это find ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -print. Имя этого пути должно точно соответствовать тому, что находил бы вывод find, если собирался распечатать каталог.
TLDR: понять ваши корневые каталоги и настроить поиск оттуда, используя -path <excluded_path> -prune -oопцию. Не включать трейлинг/ в конце исключенного пути.
findЯ считаю, что для эффективного использования крайне важно хорошо понимать структуру каталогов вашей файловой системы. На моем домашнем компьютере установлены жесткие диски с несколькими ТБ, резервная копия которых хранится примерно в половине rsnapshot( с помощью rsync). Несмотря на то, что резервное копирование выполняется на физически независимый (дублированный) диск, он монтируется в моей системной /директории root ( ) /mnt/Backups/rsnapshot_backups/:
/mnt/Backups/rsnapshot_backups/Каталог в настоящее время занимает ~ 2,9 ТБ, с ~ 60м файлов и папок; простой просмотр этого содержимого требует времени:
## As sudo (#), to avoid numerous "Permission denied" warnings:
time find /mnt/Backups/rsnapshot_backups | wc -l
60314138## 60.3M files, folders34:07.30## 34 min
time du /mnt/Backups/rsnapshot_backups -d 03112240160/mnt/Backups/rsnapshot_backups ## 3.1 TB33:51.88## 34 min
time rsnapshot du ## << more accurate re: rsnapshot footprint2.9T/mnt/Backups/rsnapshot_backups/hourly.0/4.1G/mnt/Backups/rsnapshot_backups/hourly.1/...4.7G/mnt/Backups/rsnapshot_backups/weekly.3/2.9T total ## 2.9 TB, per sudo rsnapshot du (more accurate)2:34:54## 2 hr 35 min
Таким образом, в любое время мне нужно искать файл на моем / (корневом) разделе, я должен иметь дело с (избегать, если возможно) обходом моего раздела резервных копий.
ПРИМЕРЫ
Среди различных подходов, предложенных в этой теме ( Как исключить каталог из команды find. ), Я обнаружил, что поиск с использованием принятого ответа выполняется намного быстрее - с оговорками.
Решение 1
Допустим, я хочу найти системный файл libname-server-2.a, но не хочу искать в своих rsnapshotрезервных копиях. Чтобы быстро найти системный файл, используйте путь исключения /mnt(т. Е. Используйте /mnt, не /mnt/, или /mnt/Backups, или ...):
## As sudo (#), to avoid numerous "Permission denied" warnings:
time find /-path /mnt -prune -o -name "*libname-server-2.a*"-print
/usr/lib/libname-server-2.a
real 0m8.644s## 8.6 sec <<< NOTE!
user 0m1.669s
sys 0m2.466s## As regular user (victoria); I also use an alternate timing mechanism, as## here I am using 2>/dev/null to suppress "Permission denied" warnings:
$ START="$(date +"%s")"&& find 2>/dev/null /-path /mnt -prune -o \
-name "*libname-server-2.a*"-print; END="$(date +"%s")"; \
TIME="$((END - START))"; printf 'find command took %s sec\n'"$TIME"/usr/lib/libname-server-2.a
find command took 3 sec ## ~3 sec <<< NOTE!
... находит этот файл всего за несколько секунд, в то время как это занимает гораздо больше времени (кажется, что выполняется через все «исключенные» каталоги):
## As sudo (#), to avoid numerous "Permission denied" warnings:
time find /-path /mnt/-prune -o -name "*libname-server-2.a*"-print
find: warning:-path /mnt/ will not match anything because it ends with /./usr/lib/libname-server-2.a
real 33m10.658s## 33 min 11 sec (~231-663x slower!)
user 1m43.142s
sys 2m22.666s## As regular user (victoria); I also use an alternate timing mechanism, as## here I am using 2>/dev/null to suppress "Permission denied" warnings:
$ START="$(date +"%s")"&& find 2>/dev/null /-path /mnt/-prune -o \
-name "*libname-server-2.a*"-print; END="$(date +"%s")"; \
TIME="$((END - START))"; printf 'find command took %s sec\n'"$TIME"/usr/lib/libname-server-2.a
find command took 1775 sec ## 29.6 min
Решение 2
Другое решение, предлагаемое в этой теме ( SO # 4210042 ), также работает плохо:
## As sudo (#), to avoid numerous "Permission denied" warnings:
time find /-name "*libname-server-2.a*"-not -path "/mnt"/usr/lib/libname-server-2.a
real 33m37.911s## 33 min 38 sec (~235x slower)
user 1m45.134s
sys 2m31.846s
time find /-name "*libname-server-2.a*"-not -path "/mnt/*"/usr/lib/libname-server-2.a
real 33m11.208s## 33 min 11 sec
user 1m22.185s
sys 2m29.962s
отмечая, что всякий раз, когда вы добавляете конечный /путь к исключенному пути, findкоманда затем рекурсивно вводит (все эти) /mnt/*каталоги - что в моем случае из-за /mnt/Backups/rsnapshot_backups/*подкаталогов дополнительно включает в себя ~ 2,9 ТБ файлов для поиска! Не добавляя трейлинг, /поиск должен завершиться практически сразу (в течение нескольких секунд).
«Решение 2» ( ... -not -path <exclude path> ...) также, по-видимому, рекурсивно ищет в исключенных каталогах - не возвращает исключенные совпадения, но излишне отнимает это время поиска.
Поиск в этих rsnapshotрезервных копиях:
Чтобы найти файл в одной из моих ежечасных / ежедневных / еженедельных / ежемесячных rsnapshotрезервных копий):
$ START="$(date +"%s")"&& find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0-name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s sec\n'"$TIME"/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
find command took 312 sec ## 5.2 minutes: despite apparent rsnapshot size## (~4 GB), it is in fact searching through ~2.9 TB)
Исключая вложенный каталог:
Здесь я хочу исключить вложенный каталог, например, /mnt/Vancouver/projects/ie/claws/data/*при поиске из /mnt/Vancouver/projects/:
$ time find .-iname '*test_file*'./ie/claws/data/test_file
./ie/claws/test_file
0:01.97
$ time find .-path '*/data'-prune -o -iname '*test_file*'-print
./ie/claws/test_file
0:00.07
В сторону: Добавление -printв конце команды подавляет распечатку исключенного каталога:
Это не размер файлов, которые замедляются find, это количество записей каталога, которые он должен проверить. Поэтому гораздо хуже, если у вас есть много-много маленьких файлов (особенно, если они все связаны по нескольким ссылкам!), Чем если у вас просто несколько файлов размером в несколько гигабайт.
Тоби Спейт
@TobySpeight: хорошая мысль. Я упомянул размер пространства поиска, чтобы указать масштаб, который также содержит много файлов. Быстрый поиск в корне (/) с sudo ls -R / | wc -lуказанием ~ 76,5 млн файлов (большая часть которых резервируется, за исключением системных файлов «неконфигурированных»); /mnt/Vancouver/с ls -R | wc -lуказывает ~ 2,35 млн файлов; /home/victoria/содержит 0.668M файлов.
Виктория Стюарт
4
Вы также можете использовать регулярные выражения для включения / исключения некоторых файлов / каталогов при поиске, используя что-то вроде этого:
Я использовал findдля предоставления списка файлов xgettextи хотел опустить конкретный каталог и его содержимое. Я перепробовал множество -pathкомбинаций с, -pruneно не смог полностью исключить каталог, который хотел удалить.
Хотя мне удалось игнорировать содержимое каталога, который я хотел игнорировать, я findвернул сам каталог как один из результатов, что вызвалоxgettext к сбою в результате (не принимает каталоги; только файлы).
Мое решение было просто использовать, grep -vчтобы пропустить каталог, который я не хотел в результатах:
Есть ли аргумент для findэтого будет работать на 100%, я не могу сказать наверняка. Использование grepбыло быстрым и простым решением после некоторой головной боли.
Я не вижу причин, по которым любой из ответов с более чем 100 баллами не должен работать на Ubuntu.
Аксель Бекерт
ммм посмотрим? может потому что я их всех перепробовал?
Sixro
find везде одинаковая реализация во всех дистрибутивах Linux - одна из проекта GNU. Единственная разница может быть в версиях. Но изменения за последнее десятилетие не были такими уж агрессивными, разве что для согласования разрешений.
Из stackoverflow.com/questions/4210042/… я узнал, что синтаксис, используемый для -pathобязательного имени, должен совпадать с именем, которое находит печать, если бы, например, распечатать каталог find . -path ./.git -prune -o -print, или find $HOME/foo -path $HOME/foo/.git -prune -o -print некоторые из ответов просто говорят, -path somedirчто, к сожалению, не достаточно точен, чтобы быть полезным.
PatS
2
Для того, что мне было нужно, это работало так, находя landscape.jpgна всех серверах, начиная с root, и исключая поиск по /varкаталогу:
Очень старый вопрос, но все еще есть место для улучшений. Я нашел это случайно, пытаясь решить подобную проблему, и ни один из ответов не был удовлетворительным.
Альберто
Я execчасто использую это действие и нахожу его очень полезным. Я обычно добавляю кавычки {}в случае, если в путях к файлам есть пробелы, которые дают "{}".
Людовик Куты
@lkuty Я собирался отредактировать свой пост, чтобы отразить ваш комментарий, но после быстрого теста (без кавычек, {}работает ли для файлов с пробелами в их именах) и просмотра справочных страниц, кажется, что цитирование необходимо только избегать их следует истолковывать как пунктуацию сценария оболочки. В этом случае вы должны использовать одинарные кавычки:'{}'
Альберто
Я думаю, что я должен был использовать это, чтобы сделать cpили mvили rm. Я проверю это
Людовик Куты
1
Я попробовал команду выше, но ни один из тех, кто использует "-prune", не работает для меня. В конце концов я попробовал это с командой ниже:
find . \( -name "*" \) -prune -a !-name "directory"
find ... | while read -r file ...
. Кроме того, лучше принимать и одобрять ответы.for file in $(find .); do echo "$file"; done
. Имена с пробелами разделены, чего мы не хотим.Ответы:
Используйте
-prune
переключатель. Например, если вы хотите исключитьmisc
каталог, просто добавьте-path ./misc -prune -o
в команду find:Вот пример с несколькими каталогами:
Здесь мы исключаем dir1 , dir2 и dir3 , так как в
find
выражениях это действие, которое действует по критериям-path dir1 -o -path dir2 -o -path dir3
(если dir1 или dir2 или dir3 ), а также сtype -d
.Дальнейшие действия
-o print
, просто распечатать.источник
-print
(или любое другое действие) явно после-name
. В этом случае обе «стороны»-o
печати заканчиваются, тогда как при использовании-print
печатается только эта сторона.Because -delete implies -depth, you cannot usefully use -prune and -delete together.
Итак, как мне выполнить удаление с помощью find, если я хочу исключить определенные каталоги из удаления?find . -not -path "./.git*"
. Использование./dir*
вместо./dir/*
удаляет каталог, а также содержимое из вывода.Если у
-prune
вас не работает, это будет:Предостережение: требует прохождения всех нежелательных каталогов.
источник
-prune
не исключает сам каталог, он исключает его содержимое, что означает, что вы получите нежелательную строку в выводе с исключенным каталогом..
на*
. таким образомfind -name "*.js" -not -path "*/omitme/*"
, файлы любого каталога с именем «omitme» будут опущены на любом уровне глубины.-print
явно.Я считаю, что следующее легче рассуждать, чем другие предлагаемые решения:
Важное примечание: пути, которые вы вводите после,
-path
должны точно соответствовать тому, чтоfind
будет напечатано без исключения. Если это предложение Вас смущает только убедитесь , что используются полные пути через из всей команды , как это: . Смотрите примечание [1], если вы хотите лучшего понимания.find /full/path/ -not \( -path /full/path/exclude/this -prune \) ...
Внутри
\(
и\)
это выражение, которое будет точно соответствоватьbuild/external
(см. Важное примечание выше), и, в случае успеха, позволит избежать обхода чего-либо ниже . Затем он группируется как одно выражение с экранированными скобками и с префиксом,-not
который заставитfind
пропустить все, что соответствует этому выражению.Кто-то может спросить, не добавит ли при добавлении
-not
все остальные файлы при-prune
повторном появлении, и ответ - нет. То , как-prune
работает то , что все , что, как только это будет достигнуто, то файлы ниже этого каталога постоянно игнорируются.Это происходит из реального случая использования, когда мне нужно было вызвать yui-compressor для некоторых файлов, сгенерированных wintersmith, но исключить другие файлы, которые необходимо отправить как есть.
Примечание [1] : Если вы хотите исключить,
/tmp/foo/bar
и вы запускаете поиск, как это "find /tmp \(...
", то вы должны указать-path /tmp/foo/bar
. Если, с другой стороны, вы запускаете find, как это,cd /tmp; find . \(...
вы должны указать-path ./foo/bar
.источник
find . -not \( -path ./CVS -prune \) -type f -mtime +100 -delete find: The -delete action atomatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
-exec rm -rf {} \;
вместо-delete
.find
, это действительно очевидно, но это сбило меня с толку. Если вы ищете в текущем каталоге (указав в.
качестве пути поиска или не указывая один на всех), то вы , скорее всего , хотите , чтобы ваш шаблон после того, как-path
начать с./
, например:find -not \( -path ./.git -prune \) -type f
.find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)
следуют любые условия, которые должны соответствовать тому, что вы ищете.Здесь явно есть некоторая путаница относительно того, каким должен быть предпочтительный синтаксис для пропуска каталога.
Мнение GNU
Из GNU найти страницу руководства
аргументация
-prune
останавливаетсяfind
от спуска в каталог. Простое указание-not -path
будет все равно попадать в пропущенный каталог, но-not -path
будет ложным, когдаfind
проверяется каждый файл.Проблемы с
-prune
-prune
делает то, для чего он предназначен, но все же есть некоторые вещи, о которых вы должны позаботиться, используя его.find
печатает сокращенный каталог.-prune
работает только с-print
и без других действий.-prune
работает с любым действием, кроме-delete
. Почему это не работает с удалением? Для-delete
работы find необходимо пройти по каталогу в порядке DFS, так-delete
как сначала будут удалены листья, затем родители листьев и т. Д. Но для определения-prune
смыслаfind
необходимо обратиться к каталогу и прекратить его нисходящее движение, что явно не имеет смысла с-depth
или-delete
на.Представление
Я установил простой тест из трех самых популярных ответов на этот вопрос (заменил
-print
на,-exec bash -c 'echo $0' {} \;
чтобы показать другой пример действия). Результаты нижеВывод
Оба синтаксис f10bit в и синтаксис Daniel C. Собрал в взяли 10-25ms бежать в среднем. Синтаксис GetFree , который не используется
-prune
, занял 865 мс. Итак, да, это довольно экстремальный пример, но если вы заботитесь о времени выполнения и делаете что-то дистанционно интенсивное, вы должны использовать-prune
.Обратите внимание, что синтаксис Даниэля С. Собрала был лучшим из двух
-prune
синтаксисов; но я сильно подозреваю, что это результат некоторого кеширования, так как переключение порядка, в котором выполнялись два процесса, приводило к противоположному результату, в то время как версия без обрезки всегда была самой медленной.Тестовый скрипт
источник
-prune
я могу сказать, что редко есть какая-либо разница. Имейте в виду, что какая команда запускается в первую очередь выиграет от производительности процессора, позднее снижение производительности процессора> приведет к незначительному замедлению (я чистил кэш перед каждой командой в соответствии с предложением @ndemou)name1() name2() name3()
в тестовом скрипте @BroSlow выше, чтобы изменить порядок выполнения, чтобы получить визуальное представление о том, что я сказал. В реальной жизни это незаметно между этими двумя, хотя.Это единственный, который работал на меня.
Поиск "MyFile", исключая "Каталог". Сделайте акцент на звезды *.
источник
! -path '*/Directory/*'
к вашей команде последовательно, чтобы игнорировать несколько каталоговdocker container
только работает сsh -c "find..."
Один из вариантов - исключить все результаты, содержащие имя каталога, с помощью grep. Например:
источник
-prune
) - нет.find . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3
но может быть какой-то один способ grep.egrep -v '(dir1|dir2|dir3)'
. Однако в этом конкретном примере лучше было бы исключить каталоги внутриfind
себя.Я предпочитаю
-not
обозначения ... это более читабельно:источник
find
руководства для говорит: «Чтобы игнорировать каталог и файлы в нем, используйте -prune».find . -iname '*' -and -not -path './somePath'
не мешает входу в указанный каталог.find . -iname '*' -not -path './.git/*'
find . -not -path "*/.git*"
было бы то, что вы хотите.Используйте опцию -prune. Итак, что-то вроде:
'-Type d -name proc -prune' ищет только каталоги с именем proc, которые нужно исключить.
'-O' является оператором 'ИЛИ'.
источник
-print
в конец может улучшить результаты.find . -type d -name .hg -prune -o -name data
игнорирует содержимое (нескольких).hg
каталогов, но перечисляет.hg
сами каталоги. При этом-print
он только перечислил каталоги данных, которые я искал.-prune
определенно работает и является лучшим ответом, потому что он предотвращает спуск в каталог, который вы хотите исключить.-not -path
который все еще ищет исключенный каталог, он просто не печатает результат, что может быть проблемой, если исключенный каталог является подключенным сетевым томом или у вас нет разрешений.Сложность заключается в том, что
find
очень важно определить порядок аргументов, поэтому, если вы не получите их правильно, ваша команда может не сработать. Порядок аргументов обычно таков:{path}
: Сначала поместите все аргументы, связанные с путем, например. -path './dir1' -prune -o
{options}
: У меня больше всего успехов, когда я ставлю-name, -iname, etc
последний вариант в этой группе. Например-type f -iname '*.js'
{action}
: Вы хотите добавить-print
при использовании-prune
Вот рабочий пример:
источник
Это формат, который я использовал для исключения некоторых путей:
Я использовал это, чтобы найти все файлы не в пути ". *":
источник
Подход -path -prune также работает с подстановочными знаками в пути. Вот оператор find, который найдет каталоги для сервера git, обслуживающего несколько репозиториев git, оставив внутренние каталоги git:
источник
Чтобы исключить несколько каталогов:
Чтобы добавить каталоги, добавьте
-o -path "./dirname/*"
:Но, возможно, вам следует использовать регулярное выражение , если нужно исключить много каталогов.
источник
Есть много хороших ответов, мне просто потребовалось некоторое время, чтобы понять, для чего предназначен каждый элемент команды и какая логика стоит за ним.
find начнет поиск файлов и каталогов в текущем каталоге, отсюда и
find .
.-o
Вариант обозначает логическое ИЛИ и разделяет две части команды:Любой каталог или файл, который не является каталогом ./misc, не пройдет первый тест
-path ./misc
. Но они будут проверены против второго выражения. Если их имя соответствует шаблону, который*.txt
они получают, из-за-print
опции.Когда find достигает каталога ./misc, этот каталог удовлетворяет только первому выражению. Так что
-prune
опция будет применена к нему. Он сообщает команде find не исследовать этот каталог. Таким образом, любой файл или каталог в ./misc даже не будет проверен командой find, не будет проверен на соответствие второй части выражения и не будет напечатан.источник
Для рабочего решения (проверено на Ubuntu 12.04 (Precise Pangolin)) ...
будет искать файлы MP3 в текущей папке и подпапках, за исключением подпапки dir1.
Использование:
... чтобы исключить dir1 И dir2
источник
Хорошая уловка для того, чтобы избежать печати сокращенных каталогов - использовать
-print
(работает-exec
также) после правой стороны-or
после-prune
. Например, ...напечатает путь ко всем файлам под текущим каталогом с расширением `.j2", пропуская все скрытые каталоги. Аккуратно. Но он также напечатает на распечатке полный путь каждого каталога, который пропускается, как отмечено выше. Однако, следующее не ...
потому что по логике есть скрытый
-and
после-iname
оператора и перед -принтом. Это связывает его с правой частью-or
предложения из-за логического порядка операций и ассоциативности. Но в документах говорится, что есть скрытое,-print
если оно (или любой из его двоюродных братьев ...-print0
и т. Д.) Не указано. Так почему же не левая часть-or
печати? Очевидно (и я не понял этого после моего первого прочтения страницы руководства), это верно, если там нет-print
-ЛИ-exec
ВСЕГДА, и в этом случае -print логически разбрасывается так, что все печатается. Если даже ОДИНprint
операции стиля, выраженной в каком-либо предложении, все эти скрытые логические операции исчезают, и вы получаете только то, что вы уточнить. Честно говоря, я бы предпочел это наоборот, но потомfind
только описательных операторов, по-видимому, ничего не сделало бы, так что я думаю, что это имеет смысл, как есть. Как упомянуто выше, все это также работает-exec
, поэтому следующее дает полныйls -la
список для каждого файла с желаемым расширением, но не перечисляет первый уровень каждого скрытого каталога, ...Для меня (и других в этом потоке)
find
синтаксис довольно быстро становится довольно барочным, поэтому я всегда добавляю парены, чтобы УВЕРЕН, что я знаю, что с чем связано, поэтому я обычно создаю макрос для типа-способности и формирую все такие операторы как. ..Трудно ошибиться, настроив мир на две части. Я надеюсь, что это поможет, хотя вряд ли кто-то зачитает 30-й ответ и проголосует за него, но можно надеяться. :-)
источник
Вы можете использовать опцию чернослива для достижения этой цели. Как например:
Или обратный вариант grep «grep -v»:
Вы можете найти подробные инструкции и примеры в Linux. Команда find исключает каталоги из поиска .
источник
find . -type f -print -o -path "*/node_modules" -prune
... с использованием подстановочного знака, который пропускает "node_modules" на любом уровне; использование-print
первого варианта-type f -print
приводит к печати только этой части, поэтому сами каталоги "node_modules" не перечислены. (он также может быть отменено:find . -path "*/node_modules" -prune -o -type f -print
)./node_modules
и*/node_modules
от него. Для моего случая, когдаnode_modules
существует только в каталоге, в котором я начинаю поиск (и в этомnode_modules
каталоге), я могу использовать,find . -type f -print -o -path "./node_modules" -prune
потому что не будетnode_modules
каталога в любом другом каталоге.node_modules
подкаталог, но были также подкаталоги, которые имели свои собственные node_modules ... используя./node_modules
совпадения только с подкаталогомnode_modules
в текущем каталоге.
и удаляя его; используя*/node_modules
спички и чернослив каталог на любой глубине, так*
как Глоб соответствует любому ведущему префиксу пути, например./test5/main/node_modules
, не только./
приставка. Это*
подстановочный знак, но не как регулярное выражение.источник
find ~/Projects -name '*.js' -\! -name 'node_modules' -prune
до сих порnode_modules
find ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -print
. Имя этого пути должно точно соответствовать тому, что находил бы вывод find, если собирался распечатать каталог.кажется, работает так же, как
и легче запомнить ИМО.
источник
TLDR: понять ваши корневые каталоги и настроить поиск оттуда, используя
-path <excluded_path> -prune -o
опцию. Не включать трейлинг/
в конце исключенного пути.Пример:
find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
find
Я считаю, что для эффективного использования крайне важно хорошо понимать структуру каталогов вашей файловой системы. На моем домашнем компьютере установлены жесткие диски с несколькими ТБ, резервная копия которых хранится примерно в половинеrsnapshot
( с помощьюrsync
). Несмотря на то, что резервное копирование выполняется на физически независимый (дублированный) диск, он монтируется в моей системной/
директории root ( )/mnt/Backups/rsnapshot_backups/
:/mnt/Backups/rsnapshot_backups/
Каталог в настоящее время занимает ~ 2,9 ТБ, с ~ 60м файлов и папок; простой просмотр этого содержимого требует времени:Таким образом, в любое время мне нужно искать файл на моем
/
(корневом) разделе, я должен иметь дело с (избегать, если возможно) обходом моего раздела резервных копий.ПРИМЕРЫ
Среди различных подходов, предложенных в этой теме ( Как исключить каталог из команды find. ), Я обнаружил, что поиск с использованием принятого ответа выполняется намного быстрее - с оговорками.
Решение 1
Допустим, я хочу найти системный файл
libname-server-2.a
, но не хочу искать в своихrsnapshot
резервных копиях. Чтобы быстро найти системный файл, используйте путь исключения/mnt
(т. Е. Используйте/mnt
, не/mnt/
, или/mnt/Backups
, или ...):... находит этот файл всего за несколько секунд, в то время как это занимает гораздо больше времени (кажется, что выполняется через все «исключенные» каталоги):
Решение 2
Другое решение, предлагаемое в этой теме ( SO # 4210042 ), также работает плохо:
РЕЗЮМЕ | ВЫВОДЫ
Используйте подход, показанный в « Решении 1 »
т.е.
отмечая, что всякий раз, когда вы добавляете конечный
/
путь к исключенному пути,find
команда затем рекурсивно вводит (все эти)/mnt/*
каталоги - что в моем случае из-за/mnt/Backups/rsnapshot_backups/*
подкаталогов дополнительно включает в себя ~ 2,9 ТБ файлов для поиска! Не добавляя трейлинг,/
поиск должен завершиться практически сразу (в течение нескольких секунд).«Решение 2» (
... -not -path <exclude path> ...
) также, по-видимому, рекурсивно ищет в исключенных каталогах - не возвращает исключенные совпадения, но излишне отнимает это время поиска.Поиск в этих
rsnapshot
резервных копиях:Чтобы найти файл в одной из моих ежечасных / ежедневных / еженедельных / ежемесячных
rsnapshot
резервных копий):Исключая вложенный каталог:
Здесь я хочу исключить вложенный каталог, например,
/mnt/Vancouver/projects/ie/claws/data/*
при поиске из/mnt/Vancouver/projects/
:В сторону: Добавление
-print
в конце команды подавляет распечатку исключенного каталога:источник
find
, это количество записей каталога, которые он должен проверить. Поэтому гораздо хуже, если у вас есть много-много маленьких файлов (особенно, если они все связаны по нескольким ссылкам!), Чем если у вас просто несколько файлов размером в несколько гигабайт.sudo ls -R / | wc -l
указанием ~ 76,5 млн файлов (большая часть которых резервируется, за исключением системных файлов «неконфигурированных»);/mnt/Vancouver/
сls -R | wc -l
указывает ~ 2,35 млн файлов;/home/victoria/
содержит 0.668M файлов.Вы также можете использовать регулярные выражения для включения / исключения некоторых файлов / каталогов при поиске, используя что-то вроде этого:
Это только даст вам все JS, Vue, CSS, и т.д. файлы , но исключая все файлы в
node_modules
иvendor
папок.источник
Я использовал
find
для предоставления списка файловxgettext
и хотел опустить конкретный каталог и его содержимое. Я перепробовал множество-path
комбинаций с,-prune
но не смог полностью исключить каталог, который хотел удалить.Хотя мне удалось игнорировать содержимое каталога, который я хотел игнорировать, я
find
вернул сам каталог как один из результатов, что вызвалоxgettext
к сбою в результате (не принимает каталоги; только файлы).Мое решение было просто использовать,
grep -v
чтобы пропустить каталог, который я не хотел в результатах:Есть ли аргумент для
find
этого будет работать на 100%, я не могу сказать наверняка. Использованиеgrep
было быстрым и простым решением после некоторой головной боли.источник
Ни один из предыдущих ответов не подходит для Ubuntu. Попробуй это:
Я нашел это здесь
источник
Это подходит для меня на Mac:
Это исключит
vendor
иapp/cache
dir для поиска имени, к которому добавлен суффиксphp
.источник
Для тех из вас, кто работает в старых версиях UNIX и не может использовать -path или -not
Протестировано на SunOS 5.10 bash 3.2 и SunOS 5.11 bash 4.4
источник
Лоуренс Гонсалвес (Laurence Gonsalves ) - отличный ответ о том, как
-prune
работает, как использовать prune-option-find-in-sh .И вот общее решение:
Чтобы не печатать
/path/to/seach/
несколько раз, завернитеfind
вpushd .. popd
пару.источник
-path
обязательного имени, должен совпадать с именем, которое находит печать, если бы, например, распечатать каталогfind . -path ./.git -prune -o -print
, илиfind $HOME/foo -path $HOME/foo/.git -prune -o -print
некоторые из ответов просто говорят,-path somedir
что, к сожалению, не достаточно точен, чтобы быть полезным.Для того, что мне было нужно, это работало так, находя
landscape.jpg
на всех серверах, начиная с root, и исключая поиск по/var
каталогу:find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg
find / -maxdepth 1 -type d
список всех d irectories в/
grep -v /var
исключает `/ var 'из спискаxargs -I '{}' find '{}' -name landscape.jpg
выполнить любую команду, какfind
с каждым каталогом / результатом из спискаисточник
/
пока не исключено. Вам может понадобитьсяsed 1d
.Следующие команды работают:
Если у вас возникли проблемы с поиском, используйте
-D tree
опцию для просмотра информации анализа выражения.Или
-D all
, чтобы увидеть всю информацию о выполнении.источник
Я нашел имя функции в исходных файлах C исключая * .o и исключая * .swp и exclude (не обычный файл) и исключая вывод dir с помощью этой команды:
источник
Лучше использовать
exec
действие, чемfor
цикл:exec ... '{}' ... '{}' \;
Будет выполняться один раз для каждого файла сопоставления, заменив скобки'{}'
с текущим именем файла.Обратите внимание, что фигурные скобки заключены в одинарные кавычки, чтобы защитить их от интерпретации как пунктуации сценария оболочки * .
Ноты
* Из раздела «Примеры»
find (GNU findutils) 4.4.2
справочной страницыисточник
exec
часто использую это действие и нахожу его очень полезным. Я обычно добавляю кавычки{}
в случае, если в путях к файлам есть пробелы, которые дают"{}"
.{}
работает ли для файлов с пробелами в их именах) и просмотра справочных страниц, кажется, что цитирование необходимо только избегать их следует истолковывать как пунктуацию сценария оболочки. В этом случае вы должны использовать одинарные кавычки:'{}'
cp
илиmv
илиrm
. Я проверю этоЯ попробовал команду выше, но ни один из тех, кто использует "-prune", не работает для меня. В конце концов я попробовал это с командой ниже:
источник