Как исключить каталог в 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
46 ответов
Используйте переключатель чернослива, например, если вы хотите исключить misc
каталог просто добавить -path ./misc -prune -o
к вашей команде поиска:
find . -path ./misc -prune -o -name '*.txt' -print
Вот пример с несколькими каталогами:
find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print
Здесь мы исключаем dir1, dir2 и dir3, так как в find
выражения это действие, которое действует по критериям -path dir1 -o -path dir2 -o -path dir3
(если dir1 или dir2 или dir3), ANDed с type -d
, Дальнейшие действия -o print
Просто распечатай.
Если -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 найти страницу руководства
аргументация
-prune
упоры find
от спуска в каталог. Просто указав -not -path
все равно спустится в пропущенный каталог, но -not -path
будет ложным всякий раз, когда find
проверяет каждый файл.
Проблемы с -prune
-prune
делает то, для чего он предназначен, но все же есть некоторые вещи, о которых вы должны позаботиться, используя его.
find
печатает сокращенный каталог.- TRUE Это намеченное поведение, оно просто не сходит в него. Чтобы вообще не печатать каталог, используйте синтаксис, который логически его опускает.
-prune
работает только с-print
и никаких других действий.- НЕ ПРАВДА.
-prune
работает с любым действием, кроме-delete
, Почему не работает с удалением? За-delete
для работы нужно найти каталог в порядке 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. Sobral для выполнения работали в среднем 10-25ms. Синтаксис GetFree, который не использует -prune
, заняло 865мс. Итак, да, это довольно экстремальный пример, но если вы заботитесь о времени выполнения и делаете что-то дистанционно интенсивное, вы должны использовать -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 "$0"' {} \;
}
name2() {
find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}
name3() {
find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}
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
Это единственный, который работал на меня.
find / -name NameOfFile ! -path '*/Directory/*'
Поиск по "NameOfFile", исключая "Каталог". Сделай акцент на звезды * .
Обратите внимание, что
./
раньше и
/*
после имени папки необходимо исключить, чтобы исключить, и все, что в ней! Т.е. это работает:
# This WORKS!
find -not -path "./dir_to_exclude/*"
... но они НЕ работают:
# These do NOT work!
find -not -path "dir_to_exclude"
find -not -path "dir_to_exclude/*"
find -not -path "./dir_to_exclude"
find -not -path "./dir_to_exclude/"
Объяснение:.
в начале означает "начать в текущем каталоге ", а
*
в конце есть подстановочный знак для выбора любых вложенных файлов и вложенных папок внутри.
Оттуда я люблю трубить
grep
для поиска определенных совпадающих шаблонов на интересующих путях. Пример: поиск любого пути, который НЕ находится внутри
dir_to_exclude
каталог, и который имеет
desired_file_name.txt
в этом:
# Case-sensitive; notice I use `\.` instead of `.` when grepping, in order to
# search for the literal period (`.`) instead of the regular expression
# wildcard char, which is also a period (`.`).
find -not -path "./dir_to_exclude/*" | grep "desired_file_name\.txt"
# Case-INsensitive (use `-i` with your `grep` search)
find -not -path "./dir_to_exclude/*" | grep -i "desired_file_name\.txt"
# To make `dir_to_exclude` also case INsensitive, use the `find` `-ipath` option
# instead of `-path`:
find -not -ipath "./dir_to_exclude/*" | grep -i "desired_file_name\.txt"
Использованная литература:
- [основной ответ на этот вопрос] Как исключить каталог из find. команда
- https://unix.stackexchange.com/questions/350085/is-it-possible-to-exclude-a-directory-from-the-find-command/350172#350172
- https://unix.stackexchange.com/questions/32155/find-command-how-to-ignore-case/32158#32158
Смотрите также:
- [Мне все еще нужно изучить и прочитать это] https://www.baeldung.com/linux/find-exclude-paths
Ключевые слова: исключить каталог из команды поиска; не ищите путь с помощью find; нечувствительные к регистру команды find и grep
Один из вариантов - исключить все результаты, содержащие имя каталога, с помощью 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, которые нужно исключить.
'-O' является оператором 'ИЛИ'.
-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
Есть много хороших ответов, мне просто потребовалось некоторое время, чтобы понять, для чего предназначен каждый элемент команды и какая логика стоит за ним.
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, не будет проверен на соответствие второй части выражения и не будет напечатан.
Это формат, который я использовал для исключения некоторых путей:
$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"
Я использовал это, чтобы найти все файлы не в пути ".*":
$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"
Подход -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 \)
Хороший способ избежать печати сокращенных каталогов - использовать -print
(работает на -exec
а также) после правой части -or
после -prune
. Например,...
find . -path "*/.*" -prune -or -iname "*.j2"
напечатает путь ко всем файлам в текущем каталоге с расширением.j2, пропуская все скрытые каталоги. Аккуратно. Но он также распечатает полный путь к каждому пропущенному каталогу, как указано выше. Однако следующие нет,...
find . -path "*/.*" -prune -or -iname "*.j2" -print
потому что логически есть скрытый -and
после -iname
оператор и перед -print. Это привязывает его к правой части-or
предложение из-за логического порядка операций и ассоциативности. Но в документах говорится, что есть скрытый-print
если он (или любой из его кузенов... -print0
и т.д.) не указано. Так почему же не левая часть-or
печать? По-видимому (и я не понял этого с первого чтения страницы руководства), это правда, если там нет-print
-или -exec
ВЕЗДЕ, и в этом случае -print логически разбросан так, что все будет напечатано. Если хотя бы ОДИНprint
Операция -style выражается в любом предложении, все скрытые логические элементы удаляются, и вы получаете только то, что указали. Откровенно говоря, я бы предпочел наоборот, но тогда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-го ответа и проголосует за него, но можно надеяться.:-)
Если вы ищете высокопроизводительный ответ, то это:
find . -type d -name node_modules -prune -false -o -type f
Использовать
-false
чтобы исключить сам node_modules.
Это будет в 3 раза быстрее, чем
-not -path
подход в каталоге с 10000 файлами в node_modules.
find . -type f -not -path '*node_modules*'
И если в node_modules больше файлов, вы получите гораздо более высокую производительность.
Если кто-то изучает, как игнорировать сразу несколько путей. Вы можете использовать массивы bash (отлично работает с GNU bash, версия 4.4.20(1)-release)
#!/usr/bin/env bash
# This script helps ignore unnecessary dir paths while using the find command
EXCLUDE_DIRS=(
"! -path /*.git/*"
"! -path /*go/*"
"! -path /*.bundle/*"
"! -path /*.cache/*"
"! -path /*.local/*"
"! -path /*.themes/*"
"! -path /*.config/*"
"! -path /*.codeintel/*"
"! -path /*python2.7/*"
"! -path /*python3.6/*"
"! -path /*__pycache__/*"
)
find $HOME -type f ${EXCLUDE_DIRS[@]}
# if you like fzf
find $HOME -type f ${EXCLUDE_DIRS[@]} | fzf --height 40% --reverse
Также по какой-то причине вы не сможете игнорировать пути к каталогам / bin /.
Чтобы исключить несколько каталогов:
find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)
Чтобы добавить каталоги, добавьте -o -path "./dirname/*"
:
find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)
Но, возможно, вам следует использовать регулярное выражение, если нужно исключить много каталогов.
Для рабочего решения (проверено на Ubuntu 12.04 (Precise Pangolin))...
find ! -path "dir1" -iname "*.mp3"
будет искать файлы MP3 в текущей папке и подпапках, за исключением подпапки dir1.
Использование:
find ! -path "dir1" ! -path "dir2" -iname "*.mp3"
... чтобы исключить dir1 И dir2
find . \( -path '.**/.git' -o -path '.**/.hg' \) -prune -o -name '*.js' -print
В приведенном выше примере найдены все *.js
файлы в текущем каталоге, исключая папки .git
а также .hg
, не имеет значения, насколько глубоко эти .git
а также .hg
папки есть.
Примечание: это также работает:
find . \( -path '.*/.git' -o -path '.*/.hg' \) -prune -o -name '*.js' -print
но я предпочитаю **
обозначение для согласованности с некоторыми другими инструментами, которые здесь не по теме.
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'
кажется, работает так же, как
find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)
и легче запомнить ИМО.
Вы также можете использовать регулярные выражения для включения / исключения некоторых файлов / каталогов вашего поиска, используя что-то вроде этого:
find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*"
Это даст вам только все файлы js, vue, css и т.д., но исключая все файлы в node_modules
а также vendor
папки.
Вы можете использовать опцию чернослива для достижения этой цели. Как например:
find ./ -path ./beta/* -prune -o -iname example.com -print
Или обратный вариант grep "grep -v":
find -iname example.com | grep -v beta
Вы можете найти подробные инструкции и примеры в Linux. Команда find исключает каталоги из поиска.
Здесь уже есть много ответов; Я не хочу добавлять еще один, но я думаю, что эта информация полезна.
TLDR: понять ваши корневые каталоги и настроить поиск оттуда, используя " -prune
вариант.
Фон: у меня есть rsnapshot
(rsync
) резервное хранилище, /mnt/Backups/
, что вызывает головную боль при поиске системы (/
), поскольку эти резервные копии содержат ~ 4,5 ТБ (терра) файлов!
у меня тоже есть /mnt/Vancouver
, моя основная рабочая папка с ТБ файлов, которая резервируется [ /mnt/Backups/
а также /mnt/Vancouver/
физически (избыточно) монтируются на отдельных дисках].
Из двух главных ответов здесь ( Как исключить каталог в команде find.) Я обнаружил, что поиск системных файлов с использованием принятого ответа выполняется намного быстрее, с оговорками.
Этот
find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
находит этот файл за ~3-4 секунды; этот
find / -name "*libname-server-2.a*" -not -path "/mnt/*"
появляется (?) для рекурсии через все исключенные каталоги (глубоко вложенные rsync
снимки всех смонтированных томов), так что это займет вечность. Я предполагаю, что он ищет файлы по нескольким ТБ, так что он застрял бесконечно. Например, если я попытаюсь "время", что поиск (time find ...
), Я вижу обильный вывод - предполагая, что find
глубоко перебирает "исключенный" каталог:
...
find: ‘/mnt/Backups/rsnapshot_backups/monthly.0/snapshot_root/var/lib/udisks2’: Permission denied
...
Добавление косой черты после исключенного каталога (/mnt/
) или вложенный путь (`/mnt/Backups') приводит к тому, что этот поиск снова * принимает навсегда:
Медленный:
find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
find / -path /mnt/Vancouver -prune -o -name "*libname-server-2.a*" -print
"РЕШЕНИЕ"
Вот лучшие решения (все они выполняются в считанные секунды). Опять же, моя структура каталогов
/
root/mnt/Backups/
: резервные копии на несколько туберкулезов/mnt/Vancouver/
: многотуберкулезный рабочий каталог (резервная копия на/mnt/Backups
на отдельном диске), который я часто хочу искать/home/*
: другие точки монтирования / рабочие "диски" (например,/home/victoria
знак равно~
)
Системные файлы ( /
):
Чтобы быстро найти системный файл, исключите /mnt
(не /mnt/
или же /mnt/Backups
, ...):
$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
который находит этот файл за ~3-4 секунды.
Несистемные файлы:
Например, чтобы быстро найти файл на одном из моих двух работающих "дисков", /mnt/Vancouver/
и / или /home/victoria/
).
$ find /mnt/Vancouver/ -name "*04t8ugijrlkj.jpg"
/mnt/Vancouver/temp/04t8ugijrlkj.jpg
$ find /home/victoria -iname "*Untitled Document 1"
/home/victoria/backups/shortcuts.bak.2016.11.02/Untitled Document 1
/home/victoria/Untitled Document 1
Резервные копии:
Например, чтобы найти удаленный файл в одной из моих ежечасных / ежедневных / еженедельных / ежемесячных резервных копий).
$ find /mnt/Backups/rsnapshot_backups/daily.0 -name "*04t8ugijrlkj.jpg"
/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
В сторону: Добавление -print в конце команды подавляет распечатку исключенного каталога:
$ find / -path /mnt -prune -o -name "*libname-server-2.a*"
/mnt
/usr/lib/libname-server-2.a
$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
$
Следующие команды работают:
find . -path ./.git -prune -o -print
Если у вас возникли проблемы с поиском, используйте -D tree
возможность просмотра информации об анализе выражений.
find -D tree . -path ./.git -prune -o -print
Или -D all
, чтобы увидеть всю информацию о выполнении.
find -D all . -path ./.git -prune -o -print
Ни один из предыдущих ответов не подходит для 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
,
Я использовал 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
было быстрое и простое решение после некоторой головной боли.
Для тех из вас, кто работает в старых версиях UNIX и не может использовать -path или -not
Протестировано на 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
Вы также можете использовать
find -type f -not -name .directoryname -printf "%f\n"