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.
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.
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 {} + \;
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
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?
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.
Recherche GNU
find . ! -regex ".*[/]\.svn[/]?.*"
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
find . | grep -v \.svn
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;
Pourquoi ne dirigez-vous pas votre commande avec grep qui est facilement compréhensible:
your find command| grep -v '\.svn'
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):
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.
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.)
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
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.
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
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
wcfind
est un script de recherche que j'utilise pour supprimer automatiquement les répertoires .svn.
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.*'
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'
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é.