Как исключить каталог в 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 ответов
я нахожу, что о следующем проще рассуждать, чем о других предлагаемых решениях:
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
мышление
-prune
остановка find
от спуска в каталог. Просто укажите -not -path
все равно спустится в пропустить, а -not -path
будет false всякий раз, когда find
проверяет каждый файл.
проблемы с -prune
-prune
делает то, что он предназначен для, но все еще некоторые вещи, которые вы должны заботиться при использовании его.
-
find
печать обрезанного каталога.- правда это предполагаемое поведение, оно просто не опускается в него. Чтобы избежать печати каталога в целом, используйте синтаксис, который логически опускает.
-
-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
используйте параметр-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.
ни один из предыдущих ответов не хорош на 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 минут. Без этих исключений это займет много часов.