Как исключить каталог в find. команда

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

здесь find код, который мы используем.

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done

30 ответов


используйте переключатель чернослива, например, если вы хотите исключить


Если -prune не работает для вас, это:

find -name "*.js" -not -path "./directory/*"

я нахожу, что о следующем проще рассуждать, чем о других предлагаемых решениях:

find build -not \( -path build/external -prune \) -name \*.js

это происходит из фактического случая использования, когда мне нужно было вызвать YUI-compressor на некоторых файлах, сгенерированных wintersmith, но оставить другие файлы, которые должны быть отправлены как есть.

внутри \( и \) - Это выражение, которое будет соответствовать ровно build/external (это не если ты find ./build, например, - вам нужно чтобы изменить его на ./build/external в таком случае), и будет, на успех,избегайте прохождения чего-либо ниже. Затем это группируется как одно выражение с экранированной скобкой и префиксом -not что будет find пропустить все, что соответствовало этому выражению.

можно спросить, если добавить -not не сделает все остальные файлы скрыты -prune появляется снова, и ответ-нет. Путь -prune работает, что все, что, как только это будет достигнуто, файлы ниже этого каталога постоянно игнорируются.

, что также легко расширить, чтобы добавить дополнительные исключения. Например:

find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

здесь явно есть некоторая путаница относительно того, какой предпочтительный синтаксис для пропуска каталога должен быть.

мнение GNU

To ignore a directory and the files under it, use -prune

из GNU find man page

мышление

-prune остановка find от спуска в каталог. Просто укажите -not -path все равно спустится в пропустить, а -not -path будет false всякий раз, когда find проверяет каждый файл.

проблемы с -prune

-prune делает то, что он предназначен для, но все еще некоторые вещи, которые вы должны заботиться при использовании его.

  1. find печать обрезанного каталога.

    • правда это предполагаемое поведение, оно просто не опускается в него. Чтобы избежать печати каталога в целом, используйте синтаксис, который логически опускает.
  2. -prune работает только с -print и другие действия.

    • НЕ ТАК. -prune работает с любым действием, за исключением -delete. почему он не работает с delete? на -delete чтобы работать, find необходимо пройти каталог в порядке DFS, так как -deleteсначала удалить листья, затем родители, листьев и т. д... Но для указания -prune смысл, find необходимо попасть в каталог и остановить его спуск, что явно не имеет смысла с -depth или -delete on.

производительность

я установил простой тест из трех ответов top upvoted на этот вопрос (заменен -print С -exec bash -c 'echo ' {} \; показать другой пример действия). Результаты ниже

----------------------------------------------
# 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 ""' {} \;
.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 ""' {} \;
.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 ""' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

вывод

и f10bit это и синтаксис Даниэля С. собрала потребовалось 10-25ms для запуска в среднем. GetFree-х, который не использует -prune, взял 865ms. Итак, да, это довольно экстремальный пример, но если вы заботитесь о времени выполнения и делаете что-то удаленно интенсивное, вы должны использовать -prune.

Примечание синтаксис Даниэля С. собрала выполнил лучшее из двух -prune синтаксисы; но я сильно подозреваю, что это результат некоторого кэширования при переключении порядок, в котором они выполнялись, приводил к противоположному результату, в то время как версия без чернослива всегда была самой медленной.

Тестовый Скрипт

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo ""'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo ""' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo ""' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"$0\"\'  {} \\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\( -path \""$dir/prune_me"\" -prune \\) -exec bash -c \'echo \"$0\"\' {} \\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"$0\"\' {} \\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup

одним из вариантов было бы исключить все результаты, содержащие имя каталога с grep. Например:

find . -name '*.js' | grep -v excludeddir

Я предпочитаю -not нотации ... это более читабельно:

find . -name '*.js' -and -not -path directory

используйте параметр-prune. Итак, что-то вроде:

find . -type d -name proc -prune -o -name '*.js'

'- type d-name proc-prune ' ищет только каталоги с именем proc для исключения.
"- О "- это оператор "или".


Это единственный, который работал для меня.

find / -name NameOfFile ! -path '*/Directory/*'

Поиск " NameOfFile "за исключением"Directory". Уделяйте особое внимание звездам * .


это формат, который я использовал для исключения некоторых путей:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

я использовал это, чтобы найти все файлы не в ".*" пути:

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

-prune определенно работает и является лучшим ответом, потому что он предотвращает спуск в dir, который вы хотите исключить. -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

подход-path-prune также работает с подстановочными знаками в пути. Вот инструкция find, которая найдет каталоги для сервера git, обслуживающего несколько репозиториев git, оставляя внутренние каталоги git:

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  

для рабочего решения (протестировано на Ubuntu 12.04 (точный Pangolin))...

find ! -path "dir1" -iname "*.mp3"

будет искать MP3-файлы в текущей папке и подпапках, за исключением подпапки dir1.

использование:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

... исключить dir1 и dir2


исключить несколько каталогов:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

чтобы добавить каталоги, добавьте -o -path "./dirname/*":

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

но может быть, вы должны использовать регулярные выражения, если есть много каталогов, чтобы исключить.


вы можете использовать опцию чернослива для достижения этого. Например:

find ./ -path ./beta/* -prune -o -iname example.com -print

или обратная опция grep "grep-v":

find -iname example.com | grep -v beta

Вы можете найти подробные инструкции и примеры в Linux find команда исключить каталоги из поиска.


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

find . -path ./misc -prune -o -name '*.txt' -print

find начнет поиск файлов и каталогов в текущем каталоге, следовательно,find ..

The -o опция означает логическое ИЛИ и разделяет две части команды:

[ -path ./misc -prune ] OR [ -name '*.txt' -print ]

любой каталог или файл не the .каталог / misc не будет передавать первый тест -path ./misc. Но они будут протестированы против второго выражения. Если их название соответствует шаблону *.txt они печатаются из-за .

когда найти достигает .каталог / misc, этот каталог удовлетворяет только первому выражению. Так что -prune опция будет применена к нему. Он сообщает команде find не изучить этот каталог. Итак, любой файл или каталог./ разное даже не будет исследовано find, не будет проверено против второй части выражение и печататься не будет.


я был с помощью find предоставить список файлов для xgettext, и хотел опустить определенный каталог и его содержимое. Я пробовал много перестановок -path в сочетании с -prune, но не смог полностью исключить каталог, который я хотел ушел.

хотя я смог игнорировать содержание из каталога, который я хотел проигнорировать,find затем вернул сам каталог как один из результатов, который вызвал xgettext для сбоя в результате (не принимаем каталоги, только файлы).

моим решением было просто использовать grep -v чтобы пропустить каталог, который я не хотел в результатах:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

есть ли аргумент для find это будет работать на 100%, я не могу сказать наверняка. Используя grep было быстрым и легким решением после некоторой головной боли.


find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

Кажется, работает так же, как

find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)

и легче запомнить IMO.


 find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune

ни один из предыдущих ответов не хорош на Ubuntu. Попробуйте это:

find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"

и здесь


это подходит для меня на Mac:

find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune

Это позволит исключить vendor и app/cache dir для имени поиска, которое с суффиксом php.


для тех из вас, кто в старых версиях UNIX не может использовать -путь или -не

протестировано на SunOS 5.10 bash 3.2 и SunOS 5.11 bash 4.4

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f

how-to-use-prune-option-of-find-in-sh - отличный ответ Лоранс Гонсалвес как -prune строительство.

и вот общее решение:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

чтобы не писать /path/to/seach/ несколько раз, обернуть find на pushd .. popd пара.

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd

Я нашел имя функций в файлах источников C exclude *.O и исключить *.swp и exclude (не обычный файл) и исключить вывод dir с помощью этой команды:

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach

лучше использовать exec действие, чем for петли:

find . -path "./dirtoexclude" -prune \
    -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;

на exec ... '{}' ... '{}' \; будет выполняться один раз для каждого найденного файла, заменив скобки '{}' с текущим именем файла.

обратите внимание, что фигурные скобки заключены в одинарные кавычки, чтобы защитить их от интерпретации как пунктуация сценария оболочки*.


Примечания

* из раздела примеров find (GNU findutils) 4.4.2 человек страница


Я пробовал команду выше, но ни один из тех, кто использует "-prune", не работает для меня. В конце концов я попробовал это с помощью команды ниже:

find . \( -name "*" \) -prune -a ! -name "directory"

для того, что мне нужно, он работал так, находя landscape.jpg на всех серверах, начиная с root и исключая поиск в


это работает, потому что find тесты файлы шаблон " * foo*":

find ! -path "dir1" ! -path "dir2" -name "*foo*"

но это не работать, если вы не используете шаблон (find не тест файл). Так что find не использует свою прежнюю оценку"правда"&"false " bools. Пример неработающего варианта использования с вышеуказанной нотацией:

find ! -path "dir1" ! -path "dir2" -type f

там нет!--4--> тестирование! Поэтому, если вам нужно найти файлы без сопоставления шаблонов, используйте-prune. Кроме того, с помощью чернослива find всегда быстрее, когда он действительно пропускает эти каталоги вместо того, чтобы соответствовать ему или лучше не соответствовать ему. Поэтому в этом случае используйте что-то вроде:

find dir -not \( -path "dir1" -prune \) -not \( -path "dir2" -prune \) -type f

или:

find dir -not \( -path "dir1" -o -path "dir2" -prune \) -type f

в отношении


на FreeBSD потребители:

 find . -name '*.js' -not -path '*exclude/this/dir*'

Если каталоги поиска имеют шаблон (в моем случае большую часть времени); вы можете просто сделать это, как показано ниже:

find ./n* -name "*.tcl" 

В приведенном выше примере; он ищет во всех подкаталогах, начиная с "N".


Я нашел предложения на этой странице, и многие другие страницы просто не работают в моей системе Mac OS X. Тем не менее, я нашел вариант, который работает для меня.

большая идея состоит в том, чтобы искать Macintosh HD, но избегать обхода всех внешних томов, которые в основном являются резервными копиями Time Machine, резервными копиями изображений, подключенными общими ресурсами и архивами, но без необходимости размонтировать их все, что часто непрактично.

вот мой рабочий скрипт, который я назвал "findit".

#!/usr/bin/env bash
# inspired by http://stackoverflow.com/questions/4210042/exclude-directory-from-find-command Danile C. Sobral
# using special syntax to avoid traversing. 
# However, logic is refactored because the Sobral version still traverses 
# everything on my system

echo ============================
echo find - from cwd, omitting external volumes
date
echo Enter sudo password if requested
sudo find . -not \( \
-path ./Volumes/Archive -prune -o \
-path ./Volumes/Boot\ OS\ X -prune -o \
-path ./Volumes/C \
-path ./Volumes/Data -prune -o \
-path ./Volumes/jas -prune -o \
-path ./Volumes/Recovery\ HD -prune -o \
-path ./Volumes/Time\ Machine\ Backups -prune -o \
-path ./Volumes/SuperDuper\ Image -prune -o \
-path ./Volumes/userland -prune \
\) -name "" -print
date
echo ============================
iMac2:~ jas$

различные пути связаны с внешними томами архива, Time Machine, виртуальными машинами, другими подключенными серверами и т. д. В некоторых именах томов есть пробелы.

хорошим тестовым запуском является " индекс findit.php", потому что этот файл встречается во многих местах в моей системе. С помощью этого скрипта поиск на основном жестком диске занимает около 10 минут. Без этих исключений это займет много часов.