Często używam find
polecenia do przeszukiwania kodu źródłowego, usuwania plików, cokolwiek. Irytujące, ponieważ Subversion przechowuje duplikaty każdego pliku w swoich .svn/text-base/
katalogach, moje proste wyszukiwania kończą się uzyskaniem wielu duplikatów wyników. Na przykład, chcę rekursywnie szukać uint
w wielokrotności messages.h
i messages.cpp
plików:
# 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;
Jak mogę find
zignorować .svn
katalogi?
Aktualizacja : jeśli uaktualnisz swojego klienta SVN do wersji 1.7, nie będzie to już problemem.
Kluczową cechą zmian wprowadzonych w Subversion 1.7 jest centralizacja przechowywania metadanych kopii roboczej w jednym miejscu. Zamiast
.svn
katalogu w każdym katalogu w kopii roboczej, kopie robocze Subversion 1.7 mają tylko jeden.svn
katalog - w katalogu głównym kopii roboczej. Ten katalog zawiera (między innymi) bazę danych opartą na SQLite, która zawiera wszystkie potrzebne metadane Subversion dla tej kopii roboczej.
find ... -print0 | xargs -0 egrep ...
zamiastfind ... -exec grep ...
(nie rozwidla sięgrep
dla każdego pliku, ale dla kilku plików jednocześnie). Za pomocą tego formularza można również przycinać.svn
katalogi bez korzystania z-prune
opcji find, tj.find ... -print0 | egrep -v '/\.svn' | xargs -0 egrep ...
-exec
z+
nie rozwidlagrep
dla każdego pliku, podczas gdy używanie z;
robi. Używanie-exec
jest właściwie bardziej poprawne niż używaniexargs
. Zauważ, że polecenia takie jakls
coś robią, nawet jeśli lista argumentów jest pusta, podczas gdy polecenia takiechmod
dają błąd, jeśli nie ma wystarczających argumentów. Aby zobaczyć, co mam na myśli, po prostu spróbuj następującą komendę w katalogu, który nie ma żadnego skrypt:find /path/to/dir -name '*.sh' -print0 | xargs -0 chmod 755
. Porównaj z tego:find /path/to/dir -name '*.sh' -exec chmod 755 '{}' '+'
.grep
rezygnacja.svn
nie jest dobrym pomysłem. Chociażfind
jest wyspecjalizowany w obsłudze właściwości plików,grep
nie robi tego. W twoim przykładzie plik o nazwie „.svn.txt” również zostanie odfiltrowany przez twojeegrep
polecenie. Chociaż możesz zmodyfikować wyrażenie regularne na „^ / \. Svn $” , nadal nie jest to dobrą praktyką.-prune
Orzecznikfind
działa idealnie do filtrowania plików (według nazwy pliku lub tworzenia datownik, czy cokolwiek warunek ty zestawie). To tak, jakby nawet jeśli możesz zabić karalucha za pomocą dużego miecza, nie oznacza to, że jest to sugerowany sposób :-).Odpowiedzi:
Do wyszukiwania, czy mogę zasugerować spojrzenie na ack ? Jest świadomy kodu źródłowego
find
i jako taki automatycznie ignoruje wiele typów plików, w tym informacje o repozytorium kodu źródłowego, takie jak powyższe.źródło
ack
, ale uważam, że jest znacznie wolniejszy niż wfind -type f -name "*.[ch]" | xargs grep
przypadku dużej bazy kodu.ack
rozliczenie nie jest lepszegrep
, nie świadome źródłafind
? Niektóre przykłady użycia go do zastąpieniafind
sprawiłyby, że jest to prawdziwa odpowiedź.dlaczego nie tylko
Predykat -not neguje wszystko, co ma .svn w dowolnym miejscu na ścieżce.
W twoim przypadku tak by było
źródło
'*.svn*'
ale potem'*.svn'
. Który jest poprawny? Czy oba działają? Myślę, że tak powinno być'*.svn*'
?Następująco:
Lub alternatywnie na podstawie katalogu, a nie prefiksu ścieżki:
źródło
find . -type d -name .svn -prune -o -print
ponieważ jest trochę szybszy. Zgodnie ze standardem POSIX wyrażenia są przetwarzane jeden po drugim, w określonej kolejności. Jeśli pierwszym wyrażeniem-a
jestfalse
, drugie wyrażenie nie będzie oceniane (zwane również zwarciem i oceną ).-type d
przed-name .svn
jest teoretycznie bardziej wydajne. Jest to jednak zwykle nieznaczne, z wyjątkiem bardzo dużego drzewa katalogów.-print
za częścią ostatniego wyrażenia. Coś jakfind . -name .git -prune -o \( -type f -name LICENSE -print \)
działa zgodnie z oczekiwaniami.find . -name .svn -prune -o -name .git -prune -o -type d -print
. Może to być kilka milisekund szybsze wstawianie-type d
przed tymi dwoma-name
, ale nie jest warte dodatkowego pisania.Ignorować
.svn
,.git
i innych ukrytych katalogów (zaczynające się od kropki), spróbuj:Jeśli jednak celem
find
jest wyszukiwanie w plikach, możesz spróbować użyć tych poleceń:git grep
- specjalnie zaprojektowane polecenie do wyszukiwania wzorców w repozytorium Git.ripgrep
- który domyślnie ignoruje ukryte pliki i pliki określone w.gitignore
.Powiązane: Jak znaleźć wszystkie pliki zawierające określony tekst w systemie Linux?
źródło
Oto, co bym zrobił w twoim przypadku:
rgrep
Wbudowane polecenie Emacsa ignoruje.svn
katalog i wiele innych plików, którymi prawdopodobnie nie jesteś zainteresowany podczas wykonywaniafind | grep
. Oto, czego używa domyślnie:Ignoruje katalogi tworzone przez większość systemów kontroli wersji, a także generowane pliki dla wielu języków programowania. Możesz utworzyć alias, który wywołuje to polecenie oraz zastępuje
find
igrep
wzorce dla określonych problemów.źródło
Znajdź GNU
źródło
-type d
) - ta odpowiedź zrobiła. +1W tym celu używam grep. Umieść to w swoim ~ / .bashrc
grep automatycznie używa tych opcji przy wywołaniu
źródło
GREP_OPTIONS=xxx grep "$@"
. Oznacza to, że zmienna GREP_OPTIONS jest ustawiona tylko dla instancji grep, które uruchamiam ręcznie za pomocą 'grp'. Oznacza to, że nigdy nie dostaję sytuacji, w której uruchamiam narzędzie i wewnętrznie wywołuje grep, ale narzędzie się myli, ponieważ grep nie zachowuje się tak, jak się spodziewał. Mam też drugą funkcję „grpy”, która nazywa się „grp”, ale dodaje--include=*.py
, tylko do wyszukiwania plików w języku Python.grep --exclude=tags --exclude_dir=.git ...etc... "$@"
. Podoba mi się, że działa to jak „ack”, ale zachowuję świadomość i kontrolę nad tym, co robi.find . | grep -v \.svn
źródło
.
w.svn
wyrażeniu regularnym.| fgrep -v /.svn/
lub `| grep -F -v / .svn / `, aby wykluczyć dokładnie katalog, a nie pliki z„ .svn ”jako częścią ich nazwy.Dlaczego nie podajesz polecenia grep, co jest łatwo zrozumiałe:
źródło
.
w.svn
wyrażeniu regularnym.Utwórz skrypt o nazwie
~/bin/svnfind
:Ten skrypt zachowuje się identycznie jak zwykłe
find
polecenie, ale usuwa.svn
katalogi. W przeciwnym razie zachowanie jest identyczne.Przykład:
źródło
echo
polecenie do polecenia find i powiedzieć, które polecenie jest wykonywane?svnfind -type f
działa świetnie na mojej maszynie Red Hat.echo find "${OPTIONS[@]}"...
aby wypisał polecenie find zamiast go uruchomić.echo find ${OPTIONS[@]} ${PATHS[@]} -name .svn -type d -prune -o ( ${EXPR[@]} ) $ACTION
, To daje mi następujące dane wyjściowe:find -type f -name .svn -type d -prune -o ( -true ) -print
Pomyślałem, że dodam prostą alternatywę do postów Kaleba i innych (która szczegółowo opisuje użycie
find -prune
opcjiack
,repofind
poleceń itp.), Która ma szczególne zastosowanie do użycia opisanego w pytaniu (i innych podobnych zastosowaniach):Pod kątem wydajności, należy zawsze próbować używać
find ... -exec grep ... +
(dzięki Kenji za wskazanie na to uwagę) lubfind ... | xargs egrep ...
(przenośny) lubfind ... -print0 | xargs -0 egrep ...
(GNU; prace o nazwach zawierających spacje) zamiast zfind ... -exec grep ... \;
.Formy
find ... -exec ... +
ifind | xargs
nie rozwidlają sięegrep
dla każdego pliku, ale dla kilku plików jednocześnie, co powoduje znacznie szybsze wykonanie .Podczas korzystania z
find | xargs
formularza można także użyćgrep
do łatwo i szybko suszonych śliwek.svn
(lub dowolne katalogi lub wyrażenie regularne), to znaczyfind ... -print0 | grep -v '/\.svn' | xargs -0 egrep ...
(przydatne, gdy trzeba coś szybko i nie może być jedno, aby pamiętać, jak skonfigurowaćfind
„s-prune
logiki).find | grep | xargs
Podejście jest podobne do GNUfind
„s-regex
opcji (patrzghostdog74
” s post), ale jest bardziej przenośny (będzie również działać na platformach GNU, gdziefind
nie jest możliwe).źródło
-exec
przejściafind
: jedna kończy się na,;
a druga kończy się na+
. Ten, który kończy się na,+
zastępuje{}
listą wszystkich pasujących plików. Poza tym wyrażenie regularne'/\.svn'
pasuje do nazw plików takich jak'.svn.txt'
. Więcej informacji można znaleźć w moich komentarzach do pytania.find
narzędzia. Proszę zobaczyć-exec
część :-).W repozytorium kodu źródłowego na ogół chcę robić tylko pliki tekstowe.
Pierwszy wiersz to wszystkie pliki, z wyjątkiem plików repozytorium CVS, SVN i GIT.
Drugi wiersz wyklucza wszystkie pliki binarne.
źródło
Używam find z opcjami -not -path. Nie miałem szczęścia z suszonymi śliwkami.
znajdzie groovy pliki nie w docelowej ścieżce katalogu.
źródło
Aby rozwiązać ten problem, możesz po prostu użyć tego warunku znajdowania:
Możesz dodać więcej takich ograniczeń:
Więcej informacji na ten temat można znaleźć w sekcji strony podręcznika „Operatorzy”: http://unixhelp.ed.ac.uk/CGI/man-cgi?find
źródło
Pamiętaj, że jeśli to zrobisz
find . -type f -name 'messages.*'
wówczas
-print
jest implikowane, gdy całe wyrażenie (-type f -name 'messages.*'
) jest prawdziwe, ponieważ nie ma „akcji” (jak-exec
).Chociaż, aby przestać schodzić do niektórych katalogów, powinieneś używać wszystkiego, co pasuje do tych katalogów, i śledzić je
-prune
(co ma na celu zatrzymać schodzenie do katalogów); tak:find . -type d -name '.svn' -prune
Wartość ta ma wartość True dla katalogów .svn i możemy użyć zwarcia logicznego, wykonując to przez
-o
(OR), po czym to, co następuje po,-o
jest sprawdzane tylko wtedy, gdy pierwsza część jest False, a zatem nie jest katalogiem .svn. Innymi słowy, następujące:find . -type d -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}
będzie oceniać tylko to, co jest właściwe
-o
, mianowicie-name 'message.*' -exec grep -Iw uint {}
dla plików NIE znajdujących się w katalogach .svn.Zauważ, że ponieważ
.svn
prawdopodobnie zawsze jest to katalog (a nie na przykład plik), aw tym przypadku z pewnością nie pasuje do nazwy „message. *”, Równie dobrze możesz pominąć-type d
i zrobić:find . -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}
Na koniec zauważ, że jeśli pominiesz jakieś działanie (
-exec
to działanie), powiedz tak:find . -name '.svn' -prune -o -name 'message.*'
wtedy
-print
działanie jest sugerowane, ale będzie miało zastosowanie do CAŁEGO wyrażenia, w tym-name '.svn' -prune -o
części, i w ten sposób wydrukuje wszystkie katalogi .svn, a także pliki „message. *”, co prawdopodobnie nie jest tym, czego chcesz. Dlatego zawsze używaj „akcji” po prawej stronie wyrażenia boolowskiego, gdy używasz-prune
w ten sposób. A kiedy to działanie jest drukowane, musisz je jawnie dodać, tak:find . -name '.svn' -prune -o -name 'message.*' -print
źródło
Wypróbuj findrepo, które jest prostym narzędziem do znajdowania / grep i znacznie szybszym niż ack Użyłbyś go w tym przypadku:
źródło
wcfind
to skrypt otoki znalezienia, którego używam do automatycznego usuwania katalogów .svn.źródło
Działa to dla mnie w wierszu poleceń systemu Unix
Powyższe polecenie wyświetli PLIKI, które nie są w .svn i wykona grep, o którym wspomniałeś.
źródło
xxx.svnxxx
. Jest to ważne - na przykład, jeśli używasz git zamiast svn, często będziesz chciał dołączyć pliki takie jak .gitignore (które nie są metadanymi, to zwykły plik zawarty w repozytorium) w wynikach wyszukiwania.zwykle przesyłam wyjście przez grep jeszcze raz usuwając .svn, w moim zastosowaniu nie jest on dużo wolniejszy. typowy przykład:
LUB
źródło