Saya sering menggunakan find
perintah untuk mencari melalui kode sumber, menghapus file, apa pun. Anehnya, karena Subversion menyimpan duplikat dari setiap file di .svn/text-base/
direktori -nya, pencarian sederhana saya akhirnya mendapatkan banyak hasil duplikat. Sebagai contoh, saya ingin mencari uint
secara berulang dalam beberapa file messages.h
dan 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;
Bagaimana saya bisa mengatakan find
untuk mengabaikan .svn
direktori?
Pembaruan : Jika Anda memutakhirkan klien SVN Anda ke versi 1.7 ini tidak lagi menjadi masalah.
Fitur utama dari perubahan yang diperkenalkan pada Subversion 1.7 adalah sentralisasi penyimpanan metadata copy pekerjaan ke satu lokasi. Alih-alih
.svn
direktori di setiap direktori dalam copy pekerjaan, Subversion 1.7 copy pekerjaan hanya memiliki satu.svn
direktori — di root copy pekerjaan. Direktori ini termasuk (antara lain) database yang didukung SQLite yang berisi semua metadata yang dibutuhkan Subversion untuk copy pekerjaan itu.
find ... -print0 | xargs -0 egrep ...
sebagai gantinyafind ... -exec grep ...
(tidak bercabanggrep
untuk setiap file, tetapi untuk banyak file sekaligus). Dengan menggunakan formulir ini, Anda juga dapat memangkas.svn
direktori tanpa menggunakan-prune
opsi find, yaitufind ... -print0 | egrep -v '/\.svn' | xargs -0 egrep ...
-exec
dengan+
tidak garpugrep
untuk setiap file, saat menggunakannya dengan;
tidak. Menggunakan-exec
sebenarnya lebih benar daripada menggunakanxargs
. Harap perhatikan bahwa perintah sepertils
melakukan sesuatu bahkan jika daftar argumen kosong, sementara perintah sepertichmod
memberikan kesalahan jika ada argumen yang tidak mencukupi. Untuk melihat apa yang saya maksud, hanya mencoba perintah berikut di direktori yang tidak memiliki shell script:find /path/to/dir -name '*.sh' -print0 | xargs -0 chmod 755
. Bandingkan dengan yang satu ini:find /path/to/dir -name '*.sh' -exec chmod 755 '{}' '+'
.grep
keluar.svn
juga bukan ide yang bagus. Sementarafind
khusus untuk menangani file properti,grep
tidak. Dalam contoh Anda, file bernama '.svn.txt' juga akan difilter olehegrep
perintah Anda . Meskipun Anda dapat memodifikasi regex Anda menjadi '^ / \. Svn $' , itu masih bukan praktik yang baik untuk melakukannya. The-prune
predikatfind
karya sempurna untuk menyaring file (oleh nama file, atau penciptaan timestamp, atau kondisi apa pun yang Anda disediakan). Ini seperti bahkan jika Anda dapat membunuh seekor kecoa menggunakan pedang besar tidak berarti itu adalah cara yang disarankan untuk melakukannya :-).Jawaban:
Untuk pencarian, dapatkah saya menyarankan Anda melihat ACK ? Ini adalah kode sumber yang disadari
find
, dan karena itu akan secara otomatis mengabaikan banyak jenis file, termasuk info repositori kode sumber seperti di atas.sumber
ack
sangat banyak, tetapi saya telah menemukan itu secara substansial lebih lambat darifind -type f -name "*.[ch]" | xargs grep
ketika berhadapan dengan basis kode besar.ack
ditagih sebagai yang lebih baikgrep
, bukan sumber-sadarfind
? Beberapa contoh menggunakannya untuk menggantikanfind
akan membuat ini jawaban nyata.kenapa tidak adil?
Predikat -not meniadakan segala sesuatu yang memiliki .svn di mana saja di jalan.
Jadi dalam kasus Anda itu akan menjadi
sumber
'*.svn*'
pada awalnya tapi kemudian'*.svn'
. Mana yang benar Apakah keduanya berfungsi? Saya pikir mungkin seharusnya begitu'*.svn*'
?Sebagai berikut:
Atau, sebagai alternatif berdasarkan direktori dan bukan awalan jalur:
sumber
find . -type d -name .svn -prune -o -print
karena sedikit lebih cepat. Menurut standar POSIX , ekspresi dievaluasi satu per satu, dalam urutan yang ditentukan. Jika ekspresi pertama-a
adalahfalse
, ekspresi kedua tidak akan dievaluasi (juga disebut hubungan pendek dan evaluasi ).-type d
sebelum-name .svn
secara teoritis lebih efisien. Namun, biasanya tidak signifikan kecuali jika Anda memiliki pohon direktori yang sangat besar.-print
sebagai ekspresi terakhir. Sesuatu sepertifind . -name .git -prune -o \( -type f -name LICENSE -print \)
bekerja seperti yang diharapkan.find . -name .svn -prune -o -name .git -prune -o -type d -print
,. Mungkin beberapa milidetik lebih cepat menempatkan-type d
sebelum keduanya-name
, tetapi tidak sepadan dengan mengetik tambahan.Untuk mengabaikan
.svn
,.git
dan direktori tersembunyi lainnya (dimulai dengan titik), coba:Namun, jika tujuan penggunaan
find
mencari di dalam file, Anda dapat mencoba menggunakan perintah ini:git grep
- perintah yang dirancang khusus untuk mencari pola dalam repositori Git.ripgrep
- yang secara default mengabaikan file tersembunyi dan file yang ditentukan dalam.gitignore
.Terkait: Bagaimana cara menemukan semua file yang mengandung teks tertentu di Linux?
sumber
Inilah yang akan saya lakukan dalam kasus Anda:
rgrep
Perintah bawaan Emacs mengabaikan.svn
direktori, dan banyak lagi file yang mungkin Anda tidak tertarik ketika melakukanfind | grep
. Inilah yang digunakan secara default:Ini mengabaikan direktori yang dibuat oleh sebagian besar sistem kontrol versi, serta file yang dihasilkan untuk banyak bahasa pemrograman. Anda bisa membuat alias yang menjalankan perintah ini dan mengganti
find
dangrep
pola untuk masalah spesifik Anda.sumber
GNU temukan
sumber
-type d
) - jawaban ini berhasil. +1Saya menggunakan grep untuk tujuan ini. Letakkan ini di ~ / .bashrc Anda
grep secara otomatis menggunakan opsi ini pada doa
sumber
GREP_OPTIONS=xxx grep "$@"
. Ini berarti bahwa variabel GREP_OPTIONS hanya diset untuk instance grep yang saya jalankan secara manual menggunakan 'grp'. Ini berarti saya tidak pernah mendapatkan situasi di mana saya menjalankan alat, dan secara internal ia menyebut grep, tetapi alat tersebut menjadi bingung karena grep tidak berperilaku seperti yang diharapkan. Juga, saya memiliki fungsi kedua 'grpy', yang memanggil 'grp', tetapi menambahkan--include=*.py
, hanya mencari file Python.grep --exclude=tags --exclude_dir=.git ...etc... "$@"
. Saya suka bahwa ini berjalan seperti 'ack', tetapi saya mempertahankan kesadaran, dan mengendalikan, apa yang dilakukannya.find . | grep -v \.svn
sumber
.
di.svn
regexp.| fgrep -v /.svn/
atau `| grep F v / svn / `untuk mengecualikan persis direktori dan tidak file dengan "Svn" sebagai bagian dari nama mereka.Mengapa Anda tidak mem-pipe perintah Anda dengan grep yang mudah dimengerti:
sumber
.
di.svn
regexp.Buat skrip bernama
~/bin/svnfind
:Script ini berperilaku identik dengan
find
perintah biasa tetapi memangkas.svn
direktori. Kalau tidak, tingkah lakunya identik.Contoh:
sumber
echo
perintah find dan beri tahu saya perintah apa yang dijalankan?svnfind -type f
bekerja sangat baik pada mesin Red Hat saya.echo find "${OPTIONS[@]}"...
sehingga mencetak perintah find bukannya benar-benar menjalankannya.echo find ${OPTIONS[@]} ${PATHS[@]} -name .svn -type d -prune -o ( ${EXPR[@]} ) $ACTION
, Ini memberi saya output berikut:find -type f -name .svn -type d -prune -o ( -true ) -print
Hanya berpikir saya akan menambahkan alternatif sederhana untuk posting Kaleb dan orang lain (yang merinci penggunaan
find -prune
opsiack
,,repofind
perintah , dll.) Yang khususnya berlaku untuk penggunaan yang telah Anda jelaskan dalam pertanyaan (dan penggunaan serupa lainnya):Untuk kinerja, Anda harus selalu mencoba untuk menggunakan
find ... -exec grep ... +
(terima kasih Kenji untuk menunjukkan ini) ataufind ... | xargs egrep ...
(portable) ataufind ... -print0 | xargs -0 egrep ...
(GNU; bekerja pada nama file yang mengandung spasi) bukan darifind ... -exec grep ... \;
.Bentuk
find ... -exec ... +
danfind | xargs
tidak bercabangegrep
untuk setiap file, tetapi untuk sekelompok file sekaligus, menghasilkan eksekusi yang jauh lebih cepat .Bila menggunakan
find | xargs
formulir Anda juga dapat menggunakangrep
dengan mudah dan cepat prune.svn
(atau direktori atau ekspresi reguler), yaitufind ... -print0 | grep -v '/\.svn' | xargs -0 egrep ...
(berguna ketika Anda perlu sesuatu yang cepat dan tidak dapat diganggu untuk mengingat cara mengaturfind
's-prune
logika.)The
find | grep | xargs
Pendekatan ini mirip dengan GNUfind
's-regex
pilihan (lihatghostdog74
' s post), tetapi lebih portabel (juga akan bekerja pada platform di mana GNUfind
tidak tersedia.)sumber
-exec
beralihfind
: satu berakhir dengan;
dan yang lainnya berakhir dengan+
. Yang berakhir dengan+
diganti{}
dengan daftar semua file yang cocok. Selain itu, regex Anda juga'/\.svn'
cocok dengan nama file'.svn.txt'
. Silakan merujuk komentar saya ke pertanyaan untuk informasi lebih lanjut.find
utilitas. Silakan lihat-exec
bagian :-).Dalam repositori kode sumber, saya biasanya ingin melakukan hal-hal hanya pada file teks.
Baris pertama adalah semua file, tidak termasuk file repositori CVS, SVN, dan GIT.
Baris kedua tidak termasuk semua file biner.
sumber
Saya menggunakan find dengan opsi -not -path. Saya belum beruntung dengan pangkas.
akan menemukan file asyik tidak di jalur direktori target.
sumber
Untuk mengatasi masalah ini, Anda cukup menggunakan kondisi pencarian ini:
Anda dapat menambahkan lebih banyak batasan seperti ini:
Anda dapat menemukan informasi lebih lanjut tentang ini di bagian halaman manual "Operator": http://unixhelp.ed.ac.uk/CGI/man-cgi?find
sumber
Perhatikan bahwa jika Anda melakukannya
find . -type f -name 'messages.*'
maka
-print
tersirat ketika seluruh ekspresi (-type f -name 'messages.*'
) benar, karena tidak ada 'tindakan' (seperti-exec
).Sementara, untuk berhenti turun ke direktori tertentu, Anda harus menggunakan apa pun yang cocok dengan direktori tersebut dan mengikutinya
-prune
(yang dimaksudkan untuk berhenti turun ke direktori); seperti itu:find . -type d -name '.svn' -prune
Ini mengevaluasi ke True untuk direktori .svn, dan kita dapat menggunakan hubung singkat boolean dengan mengikuti ini dengan
-o
(OR), setelah itu apa yang mengikuti setelah-o
hanya diperiksa ketika bagian pertama adalah False, maka itu bukan direktori .svn. Dengan kata lain, berikut ini:find . -type d -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}
hanya akan mengevaluasi apa yang benar
-o
, yaitu-name 'message.*' -exec grep -Iw uint {}
, untuk file TIDAK di dalam direktori .svn.Perhatikan bahwa karena
.svn
kemungkinan selalu merupakan direktori (dan bukan misalnya file), dan dalam hal ini tentu saja tidak cocok dengan nama 'pesan. *', Anda mungkin meninggalkan-type d
dan lakukan:find . -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}
Akhirnya, perhatikan bahwa jika Anda menghilangkan tindakan (
-exec
tindakan), katakan seperti:find . -name '.svn' -prune -o -name 'message.*'
maka
-print
tindakan tersirat tetapi akan berlaku untuk ekspresi SELURUH, termasuk-name '.svn' -prune -o
bagian dan dengan demikian mencetak semua direktori .svn serta file 'pesan. *', yang mungkin bukan yang Anda inginkan. Karenanya Anda harus selalu menggunakan 'aksi' di sisi kanan ekspresi boolean saat menggunakan-prune
cara ini. Dan ketika tindakan itu dicetak, Anda harus menambahkannya secara eksplisit, seperti:find . -name '.svn' -prune -o -name 'message.*' -print
sumber
Coba findrepo yang merupakan pembungkus sederhana sekitar find / grep dan jauh lebih cepat daripada ack Anda akan menggunakannya dalam kasus ini seperti:
sumber
wcfind
adalah skrip wrapper find yang saya gunakan untuk secara otomatis menghapus direktori .svn.sumber
Ini berfungsi untuk saya di prompt Unix
Perintah di atas akan mencantumkan FILES yang tidak dengan .svn dan lakukan grep yang Anda sebutkan.
sumber
xxx.svnxxx
. Ini penting - misalnya jika Anda menggunakan git bukan svn, Anda akan sering ingin memasukkan file seperti .gitignore (yang bukan metadata, ini adalah file biasa yang termasuk dalam repo) dalam hasil dari find.saya biasanya menyalurkan output melalui grep sekali lagi menghapus .svn, dalam penggunaan saya tidak jauh lebih lambat. contoh khas:
ATAU
sumber