Как я могу заставить `find` игнорировать каталоги .svn?

Я часто использую команду find для поиска в исходном коде, удаления файлов и т. Д. К сожалению, поскольку Subversion хранит дубликаты каждого файла в своих .svn/text-base/ каталогах, мои простые поисковые запросы приводят к множеству повторяющихся результатов. Например, я хочу рекурсивно искать uint в нескольких файлах messages.h и messages.cpp:

# find -name 'messages.*' -exec grep -Iw uint {} +
./messages.cpp:            Log::verbose << "Discarding out of date message: id " << uint(olderMessage.id)
./messages.cpp:    Log::verbose << "Added to send queue: " << *message << ": id " << uint(preparedMessage->id)
./messages.cpp:                Log::error << "Received message with invalid SHA-1 hash: id " << uint(incomingMessage.id)
./messages.cpp:            Log::verbose << "Received " << *message << ": id " << uint(incomingMessage.id)
./messages.cpp:            Log::verbose << "Sent message: id " << uint(preparedMessage->id)
./messages.cpp:        Log::verbose << "Discarding unsent message: id " << uint(preparedMessage->id)
./messages.cpp:        for (uint i = 0; i < 10 && !_stopThreads; ++i) {
./.svn/text-base/messages.cpp.svn-base:            Log::verbose << "Discarding out of date message: id " << uint(olderMessage.id)
./.svn/text-base/messages.cpp.svn-base:    Log::verbose << "Added to send queue: " << *message << ": id " << uint(preparedMessage->id)
./.svn/text-base/messages.cpp.svn-base:                Log::error << "Received message with invalid SHA-1 hash: id " << uint(incomingMessage.id)
./.svn/text-base/messages.cpp.svn-base:            Log::verbose << "Received " << *message << ": id " << uint(incomingMessage.id)
./.svn/text-base/messages.cpp.svn-base:            Log::verbose << "Sent message: id " << uint(preparedMessage->id)
./.svn/text-base/messages.cpp.svn-base:        Log::verbose << "Discarding unsent message: id " << uint(preparedMessage->id)
./.svn/text-base/messages.cpp.svn-base:        for (uint i = 0; i < 10 && !_stopThreads; ++i) {
./virus/messages.cpp:void VsMessageProcessor::_progress(const string &fileName, uint scanCount)
./virus/messages.cpp:ProgressMessage::ProgressMessage(const string &fileName, uint scanCount)
./virus/messages.h:    void _progress(const std::string &fileName, uint scanCount);
./virus/messages.h:    ProgressMessage(const std::string &fileName, uint scanCount);
./virus/messages.h:    uint        _scanCount;
./virus/.svn/text-base/messages.cpp.svn-base:void VsMessageProcessor::_progress(const string &fileName, uint scanCount)
./virus/.svn/text-base/messages.cpp.svn-base:ProgressMessage::ProgressMessage(const string &fileName, uint scanCount)
./virus/.svn/text-base/messages.h.svn-base:    void _progress(const std::string &fileName, uint scanCount);
./virus/.svn/text-base/messages.h.svn-base:    ProgressMessage(const std::string &fileName, uint scanCount);
./virus/.svn/text-base/messages.h.svn-base:    uint        _scanCount;

Как я могу указать find игнорировать .svn каталоги?


Обновление: если вы обновите свой клиент SVN до версия 1.7 это больше не проблема.

Ключевой особенностью изменений, внесенных в Subversion 1.7, является централизация хранения метаданных рабочих копий в одном месте. Вместо каталога .svn в каждом каталоге в рабочей копии рабочие копии Subversion 1.7 имеют только один каталог .svn - в корне рабочей копии. Этот каталог включает (среди прочего) базу данных на базе SQLite, которая содержит все метаданные, необходимые Subversion для этой рабочей копии.


person John Kugelman    schedule 22.02.2010    source источник
comment
Для повышения производительности попробуйте использовать find ... -print0 | xargs -0 egrep ... вместо find ... -exec grep ... (разветвляется не grep для каждого файла, а для группы файлов за раз). Используя эту форму, вы также можете сократить .svn каталоги без использования опции -prune команды find, т.е. find ... -print0 | egrep -v '/\.svn' | xargs -0 egrep ...   -  person vladr    schedule 08.03.2010
comment
@Vlad: Насколько я знаю, использование -exec с + не разветвляет grep для каждого файла, тогда как использование его с ; делает. Использование -exec на самом деле более правильное, чем использование xargs. Обратите внимание, что команды типа ls что-то делают, даже если список аргументов пуст, а команды типа chmod выдают ошибку, если аргументов недостаточно. Чтобы понять, что я имею в виду, просто попробуйте выполнить следующую команду в каталоге, в котором нет сценария оболочки: find /path/to/dir -name '*.sh' -print0 | xargs -0 chmod 755. Сравните с этим: find /path/to/dir -name '*.sh' -exec chmod 755 '{}' '+'.   -  person Siu Ching Pong -Asuka Kenji-    schedule 04.04.2010
comment
@Vlad: Кроме того, grep-out .svn тоже не лучшая идея. В то время как find специализируется на обработке свойств файлов, grep нет. В вашем примере файл с именем '.svn.txt' также будет отфильтрован вашей командой egrep. Хотя вы можете изменить свое регулярное выражение на '^ / \. Svn $', это по-прежнему не рекомендуется. Предикат -prune для find отлично подходит для фильтрации файла (по имени файла, метке времени создания или любому другому условию, которое вы указали). Это похоже на то, что даже если вы можете убить таракана большим мечом, это не значит, что это рекомендуемый способ сделать это :-).   -  person Siu Ching Pong -Asuka Kenji-    schedule 04.04.2010
comment
Переход на Git устранил эту проблему (среди многих других). In создает папку .git только в корне рабочей копии, а не во всех ее папках, таких как SVN. Кроме того, папка .git не содержит простых файлов, которые можно было бы спутать с вашими фактическими файлами с такими же именами.   -  person Tronic    schedule 05.04.2010
comment
2Dan Molding: svn 1.7 создает только одну директорию верхнего уровня .svn   -  person ccpizza    schedule 19.04.2011
comment
См. Также serverfault.com/q/33308/29419.   -  person DerMike    schedule 10.04.2012


Ответы (19)


Могу я предложить вам для поиска взглянуть на ack? Это осведомленный об исходном коде find, и поэтому он автоматически игнорирует многие типы файлов, включая информацию о репозитории исходного кода, такую ​​как указанная выше.

person Brian Agnew    schedule 22.02.2010
comment
Мне очень нравится ack, но я обнаружил, что он значительно медленнее, чем find -type f -name "*.[ch]" | xargs grep, при работе с большой кодовой базой. - person John Ledbetter; 23.02.2010
comment
Джон, я являюсь автором ack, и если вы можете подробно рассказать о проблемах скорости при использовании ack и grep, я буду признателен. Они были полностью сопоставимы во всех случаях, которые я нашел. Дайте мне знать на github.com/petdance/ack/issues или напишите мне на Энди по адресу petdance.com. Thansk. - person Andy Lester; 09.04.2010
comment
Ребята, это подсказка, но точно не ответ на вопрос! :) - person dolzenko; 03.04.2012
comment
@dolzenko - я думаю, что это очень хороший ответ на вопрос и, вероятно, не стоит отрицать - person Brian Agnew; 03.04.2012
comment
Разве ack не считается лучшим grep, а не осведомленным об источниках find? Некоторые примеры его использования для замены find сделают это реальным ответом. - person michiakig; 19.01.2013
comment
Это ответ на вопрос, о котором он даже не подозревал. знак равно - person Frungi; 25.01.2014
comment
Пример ack как find: ack -g '\.clj$' (поиск всех исходных файлов Clojure). И он поддерживает -print0 для подключения к xargs; очевидно, что замена find не будет полной без подключения к xargs. - person Nate C-K; 09.03.2015

почему не просто

find . -not -iwholename '*.svn*'

Предикат -not отменяет все, что имеет .svn в любом месте пути.

Так что в вашем случае это было бы

find -not -iwholename '*.svn*' -name 'messages.*' -exec grep -Iw uint {} + \;
person whaley    schedule 20.07.2010
comment
Супер большой +1 для -not и -iwholename. Ack - это замечательно, и я использую его, но find / exec все еще используется. - person David Blevins; 01.10.2011
comment
Единственный ответ, который действительно отвечал на исходный вопрос. - person Brendon Crawford; 20.01.2012
comment
Это круто. Мне интересно найти только каталоги в SVN WC, чтобы я мог выполнить некоторую рекурсивную очистку. Добавление -типа d в верхнюю строку выше дает мне именно то, что мне нужно. - person mlerley; 07.08.2013
comment
Я не в своей тарелке, и я уверен, что меня раскритикуют за этот комментарий, но, очевидно, -not и -wholename не совместимы с POSIX. Я использовал ! вместо -not и -path вместо -iwholename и получил те же результаты. Согласно моим страницам руководства (Ubuntu 12.04) этот синтаксис совместим с POSIX. - person John; 02.11.2013
comment
Обратите внимание, что это решение оценивает все дерево каталогов, что позволяет избежать случайных каталогов, разбросанных по всему дереву, но ответ Калеба Педерсона более широко применяется, если вы в первую очередь хотите избежать повторного обращения к этим каталогам. Разница может быть огромной, при использовании варианта этого решения поиск, который я только что провел, занял 16 минут, а при использовании варианта Калеба Педерсона - всего 45 секунд! - person Mark Booth; 01.06.2018
comment
@whaley Вы сначала сказали '*.svn*', но потом '*.svn'. Какой правильный? Оба работают? Думаю, наверное, должно быть '*.svn*'? - person Keith M; 13.11.2018
comment
@KeithM - отличный улов. Этот ответ сидел здесь в течение многих лет, и я не думаю, что до сих пор кто-то уловил это. - person whaley; 14.11.2018
comment
это не идеально, потому что команда find все еще перемещается по каталогу. - person quinn; 08.07.2020

Следующее:

find . -path '*/.svn*' -prune -o -print

Или, в качестве альтернативы, на основе каталога, а не префикса пути:

find . -name .svn -a -type d -prune -o -print
person Kaleb Pederson    schedule 22.02.2010
comment
@ Калеб: Привет. Я предлагаю find . -type d -name .svn -prune -o -print, потому что это немного быстрее. Согласно стандарту POSIX выражения вычисляются одно за другим, в указанном порядке. Если первое выражение в -a равно false, второе выражение не будет оцениваться (также называется коротким замыканием и оценка). - person Siu Ching Pong -Asuka Kenji-; 04.04.2010
comment
@Kaleb: сравнение типа файла (эквивалентное проверке, установлен ли бит в целое число) быстрее, чем сравнение имени файла (эквивалент к сравнению строк, которое равно O (n)), размещение -type d перед -name .svn теоретически более эффективно. Однако обычно это несущественно, за исключением случаев, когда у вас очень большое дерево каталогов. - person Siu Ching Pong -Asuka Kenji-; 04.04.2010
comment
@Siu - Хорошее замечание. Точно так же, если у вас есть какая-либо проверка, которая может быть выполнена быстро (например, O (1)) и позволяет избежать многих дополнительных проверок, рекомендуется сначала разместить эту проверку. - person Kaleb Pederson; 05.04.2010
comment
Это не сработает, если я добавлю другие условия вместо «-print». Например, если я хочу найти все файлы (не каталоги), но исключить каталог '.git' и его содержимое, я пробую find . -path './.git' -prune -o -type f, который включает все файлы и исключает содержимое '.git', но не исключает сам каталог '.git'. - person Jonathan Hartley; 08.07.2015
comment
@ SiuChingPong-AsukaKenji- нет, сравнение только имени файла выполняется быстрее, потому что -type требует вызова stat (2) для каждого файла. Однако имя файла является частью ответа readdir (3). - person hraban; 17.09.2015
comment
@JonathanHartley Вам не хватает -print в последнем выражении. Что-то вроде find . -name .git -prune -o \( -type f -name LICENSE -print \) работает как положено. - person sschuberth; 21.07.2016
comment
Если вы хотите игнорировать .git и .svn и просто перечислить другие каталоги, find . -name .svn -prune -o -name .git -prune -o -type d -print. Установка -type d перед двумя -name может оказаться на несколько миллисекунд быстрее, но это не стоит дополнительного набора текста. - person JPaget; 06.05.2019

Чтобы игнорировать .svn, .git и другие скрытые каталоги (начинающиеся с точки), попробуйте:

find . -type f -not -path '*/\.*'

Однако, если целью использования find является поиск в файлах, вы можете попробовать использовать следующие команды:

  • git grep - специально разработанная команда для поиска шаблонов в репозитории Git.
  • ripgrep - который по умолчанию игнорирует скрытые файлы и файлы, указанные в .gitignore.

По теме: Как мне найти все файлы, содержащие определенный текст, в Linux?

person kenorb    schedule 20.04.2015
comment
Лучший ответ имо. Остальные пытаются объяснить вещи, которые не отвечают на простой вопрос. - person Anthony; 17.08.2018
comment
это не сработает, если вы попытаетесь исключить каталог из соображений производительности - person quinn; 08.07.2020

Вот что я бы сделал в вашем случае:

find . -path .svn -prune -o -name messages.* -exec grep -Iw uint {} +

Встроенная команда Emacs rgrep игнорирует каталог .svn и многие другие файлы, которые вам, вероятно, неинтересны при выполнении find | grep. Вот что он использует по умолчанию:

find . \( -path \*/SCCS -o -path \*/RCS -o -path \*/CVS -o -path \*/MCVS \
          -o -path \*/.svn -o -path \*/.git -o -path \*/.hg -o -path \*/.bzr \
          -o -path \*/_MTN -o -path \*/_darcs -o -path \*/\{arch\} \) \
     -prune -o \
       \( -name .\#\* -o -name \*.o -o -name \*\~ -o -name \*.bin -o -name \*.lbin \
          -o -name \*.so -o -name \*.a -o -name \*.ln -o -name \*.blg \
          -o -name \*.bbl -o -name \*.elc -o -name \*.lof -o -name \*.glo \
          -o -name \*.idx -o -name \*.lot -o -name \*.fmt -o -name \*.tfm \
          -o -name \*.class -o -name \*.fas -o -name \*.lib -o -name \*.mem \
          -o -name \*.x86f -o -name \*.sparcf -o -name \*.fasl -o -name \*.ufsl \
          -o -name \*.fsl -o -name \*.dxl -o -name \*.pfsl -o -name \*.dfsl \
          -o -name \*.p64fsl -o -name \*.d64fsl -o -name \*.dx64fsl -o -name \*.lo \
          -o -name \*.la -o -name \*.gmo -o -name \*.mo -o -name \*.toc \
          -o -name \*.aux -o -name \*.cp -o -name \*.fn -o -name \*.ky \
          -o -name \*.pg -o -name \*.tp -o -name \*.vr -o -name \*.cps \
          -o -name \*.fns -o -name \*.kys -o -name \*.pgs -o -name \*.tps \
          -o -name \*.vrs -o -name \*.pyc -o -name \*.pyo \) \
     -prune -o \
     -type f \( -name pattern \) -print0 \
     | xargs -0 -e grep -i -nH -e regex

Он игнорирует каталоги, созданные большинством систем контроля версий, а также сгенерированные файлы для многих языков программирования. Вы можете создать псевдоним, вызывающий эту команду, и заменить шаблоны find и grep для ваших конкретных проблем.

person Antoine    schedule 21.11.2011

GNU найти

find .  ! -regex ".*[/]\.svn[/]?.*"
person ghostdog74    schedule 23.02.2010
comment
Я загружал пути к каталогам в массив для обработки PHP. Другие ответы выше (по какой-либо причине) не отфильтровали файлы в находке (несмотря на -type d) - этот ответ сделал. +1 - person b. e. hollenbeck; 30.12.2011

Для этого я использую grep. Поместите это в свой ~ / .bashrc

export GREP_OPTIONS="--binary-files=without-match --color=auto --devices=skip --exclude-dir=CVS --exclude-dir=.libs --exclude-dir=.deps --exclude-dir=.svn"

grep автоматически использует эти параметры при вызове

person Ronny Brendel    schedule 08.03.2010
comment
Стоит отметить, что grep получил параметр --exclude-dir только год или два назад. Последние дистрибутивы Linux включают его, но если я правильно помню, мне пришлось скомпилировать свой собственный grep (или попросить Homebrew сделать это) на OSX. - person Jonathan Hartley; 08.07.2015
comment
Я использую второстепенный вариант этого. Мой .bashrc создает функцию Bash 'grp', которая определяется как GREP_OPTIONS=xxx grep "$@". Это означает, что переменная GREP_OPTIONS устанавливается только для экземпляров grep, которые я запускаю вручную с помощью grp. Это означает, что у меня никогда не бывает ситуации, когда я запускаю инструмент, и внутри он вызывает grep, но инструмент сбивается с толку, потому что grep ведет себя не так, как ожидалось. Кроме того, у меня есть вторая функция grpy, которая вызывает grp, но добавляет --include=*.py, чтобы просто искать файлы Python. - person Jonathan Hartley; 08.07.2015
comment
На самом деле, поразмыслив, я больше не использую GREP_OPTIONS. Теперь у меня есть только функция оболочки grp, которая вызывает grep --exclude=tags --exclude_dir=.git ...etc... "$@". Мне нравится, что это работает как «ack», но я сохраняю понимание и контроль над тем, что он делает. - person Jonathan Hartley; 09.08.2017

Создайте скрипт под названием ~/bin/svnfind:

#!/bin/bash
#
# Attempts to behave identically to a plain `find' command while ignoring .svn/
# directories.

OPTIONS=()
PATHS=()
EXPR=()

while [[ $1 =~ ^-[HLP]+ ]]; do
    OPTIONS+=("$1")
    shift
done

while [[ $# -gt 0 ]] && ! [[ $1 =~ '^[-(),!]' ]]; do
    PATHS+=("$1")
    shift
done

# If user's expression contains no action then we'll add the normally-implied
# `-print'.
ACTION=-print

while [[ $# -gt 0 ]]; do
    case "$1" in
       -delete|-exec|-execdir|-fls|-fprint|-fprint0|-fprintf|-ok|-print|-okdir|-print0|-printf|-prune|-quit|-ls)
            ACTION=;;
    esac

    EXPR+=("$1")
    shift
done

if [[ ${#EXPR} -eq 0 ]]; then
    EXPR=(-true)
fi

exec -a "$(basename "$0")" find "${OPTIONS[@]}" "${PATHS[@]}" -name .svn -type d -prune -o '(' "${EXPR[@]}" ')' $ACTION

Этот сценарий ведет себя идентично простой команде find, но удаляет .svn каталоги. В остальном поведение идентично.

Пример:

# svnfind -name 'messages.*' -exec grep -Iw uint {} +
./messages.cpp:            Log::verbose << "Discarding out of date message: id " << uint(olderMessage.id)
./messages.cpp:    Log::verbose << "Added to send queue: " << *message << ": id " << uint(preparedMessage->id)
./messages.cpp:                Log::error << "Received message with invalid SHA-1 hash: id " << uint(incomingMessage.id)
./messages.cpp:            Log::verbose << "Received " << *message << ": id " << uint(incomingMessage.id)
./messages.cpp:            Log::verbose << "Sent message: id " << uint(preparedMessage->id)
./messages.cpp:        Log::verbose << "Discarding unsent message: id " << uint(preparedMessage->id)
./messages.cpp:        for (uint i = 0; i < 10 && !_stopThreads; ++i) {
./virus/messages.cpp:void VsMessageProcessor::_progress(const string &fileName, uint scanCount)
./virus/messages.cpp:ProgressMessage::ProgressMessage(const string &fileName, uint scanCount)
./virus/messages.h:    void _progress(const std::string &fileName, uint scanCount);
./virus/messages.h:    ProgressMessage(const std::string &fileName, uint scanCount);
./virus/messages.h:    uint        _scanCount;
person Community    schedule 22.02.2010
comment
Этот сценарий работает не так, как я ожидал. При запуске с svnfind -type f он также печатает svn-каталогов и файлы в svn-каталогах. - person Wolkenarchitekt; 10.01.2011
comment
@ifischer Можете ли вы добавить echo к команде поиска и сказать мне, какая команда выполняется? svnfind -type f отлично работает на моей машине Red Hat. - person John Kugelman; 10.01.2011
comment
Хорошо, похоже, это зависит от ОС. Я использую Debian Squeeze (то же самое в Ubuntu). Я не понимаю, что вы имеете в виду под добавлением эха? - person Wolkenarchitekt; 10.01.2011
comment
@ifischer Измените последнюю строку на echo find "${OPTIONS[@]}"..., чтобы она печатала команду поиска, а не выполняла ее. - person John Kugelman; 10.01.2011
comment
Хорошо, изменил последнюю строку на echo find ${OPTIONS[@]} ${PATHS[@]} -name .svn -type d -prune -o ( ${EXPR[@]} ) $ACTION. Это дает мне следующий результат: find -type f -name .svn -type d -prune -o ( -true ) -print - person Wolkenarchitekt; 10.01.2011
comment
@ifischer Я обновил второй цикл while. Можете ли вы попробовать сценарий сейчас? - person John Kugelman; 10.01.2011
comment
Тем не менее svnfind -type f дает мне также файлы, лежащие в каталогах .svn - person Wolkenarchitekt; 10.01.2011
comment
@ifischer Хорошо, если вы можете понять, почему PATHS и / или OPTIONS заполняются неправильно, я был бы признателен. Они должны быть пустыми, а -type f должен оказаться в EXPR. - person John Kugelman; 11.01.2011
comment
Спасибо за вашу помощь. но я напишу свой собственный вариант поиска с поддержкой svn (без grep и со всеми функциями поиска), который, надеюсь, будет просто однострочным. Выложу здесь, когда заработает. - person Wolkenarchitekt; 11.01.2011

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

your find command| grep -v '\.svn'
person Vijay    schedule 24.02.2010
comment
Вы должны экранировать . в .svn регулярном выражении. - person vladr; 08.03.2010
comment
@Yclian без тени сомнения; если вы этого не сделаете, каталоги с именами 'tsvn', '1svn', 'asvn' и т. д. также будут проигнорированы, поскольку '.' - это подстановочный знак регулярного выражения: «соответствует любому символу». - person vladr; 20.07.2010
comment
Хорошо, я думал, что это произойдет только в случае -E и -G. Я только что проверил, мой плохой. :( - person yclian; 21.07.2010
comment
Мне нравится этот ответ, потому что он концептуально проще, чем все остальные. Я не могу вспомнить нелепый синтаксис для использования 'find', но я точно могу вспомнить, как использовать grep -v, поскольку он используется во многих ситуациях. - person mattismyname; 19.01.2015

Просто подумал, что добавлю простую альтернативу к сообщениям Калеба и других (в которых подробно описано использование параметра find -prune, ack, repofind команд и т. Д.), Что особенно применимо к использованию вами описали в вопросе (и любых других подобных случаях):

  1. Для повышения производительности вы всегда должны пытаться использовать find ... -exec grep ... + (спасибо Kenji за указание на это) или find ... | xargs egrep ... (переносимый) или find ... -print0 | xargs -0 egrep ... (GNU; работает с именами файлов, содержащими пробелы) вместо find ... -exec grep ... \;.

    Формы find ... -exec ... + и find | xargs не разветвляют egrep для каждого файла, а скорее для группы файлов за раз, что приводит к гораздо более быстрому выполнению.

  2. При использовании формы find | xargs вы также можете использовать grep для простого и быстрого удаления .svn (или любых каталогов или регулярных выражений), то есть find ... -print0 | grep -v '/\.svn' | xargs -0 egrep ... (полезно, когда вам нужно что-то быстрое и вам не нужно вспоминать, как настроить логику find -prune. )

    Подход find | grep | xargs похож на вариант -regex GNU find (см. Сообщение ghostdog74), но более переносимый (также будет работать на платформах, где GNU find недоступен).

person vladr    schedule 08.03.2010
comment
@Vlad: Обратите внимание, что есть две формы для переключателя -exec в find: одна заканчивается на ;, а другая заканчивается на +. Тот, который заканчивается на +, заменяет {} списком всех совпадающих файлов. Кроме того, ваше регулярное выражение '/\.svn' также соответствует таким именам файлов, как '.svn.txt'. Пожалуйста, обратитесь к моим комментариям к вопросу для получения дополнительной информации. - person Siu Ching Pong -Asuka Kenji-; 04.04.2010
comment
@Vlad: Вот стандарт POSIX для find утилита. См. Часть -exec :-). - person Siu Ching Pong -Asuka Kenji-; 04.04.2010

В репозитории исходного кода я обычно хочу делать что-то только с текстовыми файлами.

Первая строка - это все файлы, за исключением файлов репозитория CVS, SVN и GIT.

Вторая строка исключает все двоичные файлы.

find . -not \( -name .svn -prune -o -name .git -prune -o -name CVS -prune \) -type f -print0 | \
xargs -0 file -n | grep -v binary | cut -d ":" -f1
person rickfoosusa    schedule 07.03.2014

Я использую find с параметрами -not -path. С черносливом мне не повезло.

find .  -name "*.groovy" -not -path "./target/*" -print

найдет файлы groovy не в пути к целевому каталогу.

person scott m gardner    schedule 13.06.2014

Чтобы решить эту проблему, вы можете просто использовать это условие поиска:

find \( -name 'messages.*' ! -path "*/.svn/*" \) -exec grep -Iw uint {} +

Вы можете добавить дополнительные ограничения, например:

find \( -name 'messages.*' ! -path "*/.svn/*" ! -path "*/CVS/*" \) -exec grep -Iw uint {} +

Дополнительную информацию об этом можно найти в разделе "Операторы" на странице руководства: http://unixhelp.ed.ac.uk/CGI/man-cgi?find

person Code-Source    schedule 17.09.2014

Обратите внимание, что если вы это сделаете

find . -type f -name 'messages.*'

тогда -print подразумевается, когда все выражение (-type f -name 'messages.*') истинно, потому что нет никакого «действия» (например, -exec).

В то время как, чтобы прекратить спускаться в определенные каталоги, вы должны использовать все, что соответствует этим каталогам, и следовать за ним -prune (который предназначен для остановки перехода в каталоги); вот так:

find . -type d -name '.svn' -prune

Это оценивается как Истина для каталогов .svn, и мы можем использовать логическое короткое замыкание, следуя за ним -o (ИЛИ), после чего то, что следует после -o, проверяется только тогда, когда первая часть - Ложь. , следовательно, это не каталог .svn. Другими словами, следующее:

find . -type d -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}

будет оценивать только то, что правильно от -o, а именно -name 'message.*' -exec grep -Iw uint {}, для файлов НЕ внутри каталогов .svn.

Обратите внимание: поскольку .svn, скорее всего, всегда является каталогом (а не, например, файлом), и в этом случае определенно не соответствует имени 'message. *', Вы также можете оставить -type d и сделать:

find . -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}

Наконец, обратите внимание, что если вы опускаете какое-либо действие (-exec - это действие), скажите так:

find . -name '.svn' -prune -o -name 'message.*'

тогда подразумевается действие -print, но оно будет применяться к выражению WHOLE, включая часть -name '.svn' -prune -o, и, таким образом, распечатать все каталоги .svn, а также файлы 'message. *', что, вероятно, не то, что вам нужно. Поэтому вы всегда должны использовать «действие» в правой части логического выражения при использовании -prune таким образом. И когда это действие печатается, вы должны явно добавить его, например:

find . -name '.svn' -prune -o -name 'message.*' -print

person Carlo Wood    schedule 26.12.2016

Попробуйте findrepo, который представляет собой простую оболочку для find / grep и работает намного быстрее, чем ack В этом случае вы бы использовали его как:

findrepo uint 'messages.*'
person pixelbeat    schedule 23.02.2010

wcfind - это сценарий оболочки поиска, который я использую для автоматического удаления Каталоги .svn.

person leedm777    schedule 08.03.2010

У меня это работает в командной строке Unix

gfind. \ (-not -wholename '* \. svn *' \) -type f -name 'messages. *' -exec grep -Iw uint {} +

Приведенная выше команда перечислит ФАЙЛЫ, которые не имеют .svn, и выполнит указанную вами команду grep.

person Felix    schedule 09.01.2012
comment
"gfind" - опечатка? У меня его нет на Ubuntu 14.04. - person Jonathan Hartley; 08.07.2015
comment
Предполагая, что вы имели в виду «найти», это не совсем сработает. Он также отфильтровывает такие файлы, как xxx.svnxxx. Это важно - например, если вы используете git вместо svn, вам часто нужно включать такие файлы, как .gitignore (который не является метаданными, это обычный файл, который включен в репо) в результаты поиска. - person Jonathan Hartley; 08.07.2015

Я обычно передаю вывод через grep еще раз, удаляя .svn, в моем использовании это не намного медленнее. типичный пример:

find -name 'messages.*' -exec grep -Iw uint {} + | grep -Ev '.svn|.git|.anythingElseIwannaIgnore'

OR

find . -type f -print0 | xargs -0 egrep messages. | grep -Ev '.svn|.git|.anythingElseIwannaIgnore'
person geminiimatt    schedule 19.03.2013

person    schedule
comment
Вы должны экранировать . в .svn регулярном выражении. - person vladr; 08.03.2010
comment
Используйте --fixed-strings с grep: | fgrep -v /.svn/ или `| grep -F -v / .svn / `, чтобы исключить точно каталог, а не файлы с .svn как частью их имени. - person Stephen P; 29.01.2011