web-dev-qa-db-fra.com

Comment puis-je obtenir que 'find` ignore les répertoires .svn?

J'utilise souvent la commande find pour rechercher dans le code source, supprimer des fichiers, peu importe. Ennuyé, car Subversion stocke les doublons de chaque fichier dans son .svn/text-base/ répertoires mes recherches simples aboutissent à de nombreux résultats en double. Par exemple, je veux rechercher récursivement uint dans plusieurs messages.h et messages.cpp des dossiers:

# 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;

Comment puis-je dire à find d'ignorer le .svn répertoires?


Mise à jour : Si vous mettez à niveau votre client SVN vers version 1.7 , ce n'est plus un problème.

Une caractéristique clé des modifications introduites dans Subversion 1.7 est la centralisation du stockage des métadonnées de la copie de travail dans un emplacement unique. Au lieu d'une .svn répertoire dans chaque répertoire de la copie de travail, les copies de travail de Subversion 1.7 n’ont qu’un seul .svn répertoire: à la racine de la copie de travail. Ce répertoire inclut (entre autres) une base de données basée sur SQLite qui contient toutes les métadonnées dont Subversion a besoin pour cette copie de travail.

219
John Kugelman

Pour la recherche, puis-je vous suggérer de regarder ack ? Il s'agit d'un find sensible au code source et, en tant que tel, ignorera automatiquement de nombreux types de fichiers, y compris les informations de référentiel de code source telles que celles décrites ci-dessus.

64
Brian Agnew

pourquoi pas juste

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

Le prédicat -not annule tout ce qui contient .svn n'importe où dans le chemin.

Donc dans votre cas ce serait

find -not -iwholename '*.svn*' -name 'messages.*' -exec grep -Iw uint {} + \;
287
whaley

Comme suit:

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

Ou, alternativement, basé sur un répertoire et non sur un préfixe de chemin:

find . -name .svn -a -type d -Prune -o -print
140
Kaleb Pederson

Ignorer .svn, .git et d’autres répertoires cachés (commençant par un point), essayez:

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

Cependant, si le but d'utiliser find est de chercher dans les fichiers, vous pouvez essayer d'utiliser ces commandes:

  • git grep - commande spécialement conçue pour rechercher des modèles dans le référentiel Git.
  • ripgrep - qui ignore par défaut les fichiers cachés et les fichiers spécifiés dans .gitignore.

Related: Comment trouver tous les fichiers contenant du texte spécifique sous Linux?

31
kenorb

Voici ce que je ferais dans votre cas:

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

La commande intégrée rgrep d'Emacs ignore .svn répertoire, et de nombreux autres fichiers qui ne vous intéressent probablement pas lors de l'exécution d'un find | grep. Voici ce qu'il utilise par défaut:

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

Il ignore les répertoires créés par la plupart des systèmes de contrôle de version, ainsi que les fichiers générés pour de nombreux langages de programmation. Vous pouvez créer un alias qui appelle cette commande et remplacer les modèles find et grep pour vos problèmes spécifiques.

18
Antoine

Recherche GNU

find .  ! -regex ".*[/]\.svn[/]?.*"
12
ghostdog74

J'utilise grep à cette fin. Mettez ceci dans votre ~/.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 utilise automatiquement ces options lors de l'appel

10
Ronny Brendel

find . | grep -v \.svn

8
me.

Créez un script appelé ~/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

Ce script se comporte de manière identique à une commande simple find mais il élague .svn répertoires. Sinon le comportement est identique.

Exemple:

# 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;
8
John Kugelman

Pourquoi ne dirigez-vous pas votre commande avec grep qui est facilement compréhensible:

your find command| grep -v '\.svn'
7
Vijay

Je pensais juste que j'ajouterais ne alternative simple aux messages de Kaleb et d'autres (qui détaillaient l'utilisation de l'option find -Prune, des commandes ack, repofind etc.) qui est particulièrement applicable à l'usage que vous avez décrit dans la question (et à tout autre usage similaire):

  1. Pour des performances, vous devriez toujours essayer d’utiliser find ... -exec grep ... + (merci Kenji de l’avoir signalé) ou find ... | xargs egrep ... (portable) ou find ... -print0 | xargs -0 egrep ... (GNU; fonctionne sur les noms de fichiers contenant des espaces) à la place de find ... -exec grep ... \;.

    Le formulaire find ... -exec ... + et find | xargs ne divise pas egrep pour chaque fichier, mais plutôt pour un groupe de fichiers à la fois, ce qui entraîne exécution beaucoup plus rapide.

  2. Lorsque vous utilisez le formulaire find | xargs, vous pouvez également utiliser grep pour supprimer facilement et rapidement .svn (ou tout répertoire ou expression régulière), c.-à-d. find ... -print0 | grep -v '/\.svn' | xargs -0 egrep ... (utile lorsque vous avez besoin de quelque chose rapide et ne vous inquiétez pas de savoir comment configurer la logique -Prune de find.)

    L’approche find | grep | xargs est similaire à l’option -regex de GNU find (voir le post de ghostdog74), mais elle est plus portable (elle fonctionnera également plates-formes où GNU find n'est pas disponible.)

5
vladr

Dans un référentiel de code source, je souhaite généralement faire des choses uniquement avec les fichiers texte.

La première ligne regroupe tous les fichiers, à l'exclusion des fichiers de référentiel CVS, SVN et GIT.

La deuxième ligne exclut tous les fichiers binaires.

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
4
rickfoosusa

J'utilise find avec les options -not -path. Je n'ai pas eu de chance avec Prune.

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

trouvera les fichiers groovy pas dans le chemin du répertoire cible.

3
scott m gardner

Notez que si vous le faites

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

alors -print est impliqué lorsque l'expression entière (-type f -name 'messages.*') est vraie, car il n'y a pas d'action (comme -exec).

Alors que, pour arrêter de descendre dans certains répertoires, vous devez utiliser tout ce qui correspond à ces répertoires et le suivre avec -Prune (Qui est destiné à arrêter de descendre dans les répertoires); ainsi:

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

Ceci est évalué à True pour les répertoires .svn, et nous pouvons utiliser un court-circuit booléen en suivant ceci avec -o (OR), après quoi ce qui suit après le -o n’est cochée que lorsque la première partie est False, donc not un répertoire .svn. En d'autres termes, les éléments suivants:

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

n'évalue que ce qui est juste du -o, à savoir -name 'message.*' -exec grep -Iw uint {}, pour les fichiers NON situés dans les répertoires .svn.

Notez que parce que .svn Est probablement toujours un répertoire (et non par exemple un fichier), et que dans ce cas ne correspond certainement pas au nom 'message. *', Vous pouvez également laisser de côté le -type d Et faire:

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

Enfin, notez que si vous omettez une action (-exec Est une action), dites comme ceci:

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

alors l'action -print est implicite mais s'appliquera à l'expression ENTIÈRE, y compris la partie -name '.svn' -Prune -o et imprimera ainsi tous les répertoires .svn ainsi que les fichiers 'message. *', qui ne sont probablement pas ce que tu veux. Par conséquent, vous devez toujours utiliser une "action" dans la partie droite de l'expression booléenne lorsque vous utilisez -Prune De cette manière. Et lorsque cette action est en cours d'impression, vous devez l'ajouter explicitement, comme suit:

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

2
Carlo Wood

Pour résoudre ce problème, vous pouvez simplement utiliser cette condition de recherche:

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

Vous pouvez ajouter plus de restriction comme ceci:

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

Vous trouverez plus d’informations à ce sujet dans la section "Opérateurs" de la page de manuel: http://unixhelp.ed.ac.uk/CGI/man-cgi?find

2
Code-Source

wcfind est un script de recherche que j'utilise pour supprimer automatiquement les répertoires .svn.

2
leedm777

Essayez findrepo qui est un simple wrapper autour de find/grep et beaucoup plus rapide que ack. Vous l'utiliseriez dans ce cas comme:

findrepo uint 'messages.*'
2
pixelbeat

en règle générale, je réachemine la sortie via grep en supprimant .svn. Dans mon utilisation, elle n’est pas beaucoup plus lente. exemple typique:

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'
1
geminiimatt

Cela fonctionne pour moi dans l'invite Unix

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

La commande ci-dessus listera les fichiers qui ne sont pas avec .svn et fera le grep que vous avez mentionné.

1
Felix