ฉันจะหา `find 'เพื่อละเว้นไดเรกทอรี. svn ได้อย่างไร


227

ฉันมักจะใช้findคำสั่งเพื่อค้นหาผ่านซอร์สโค้ดลบไฟล์อะไรก็ตาม น่ารำคาญเพราะการโค่นล้มเก็บข้อมูลที่ซ้ำกันของแต่ละไฟล์ใน.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จะไม่มีปัญหาอีกต่อไป

คุณสมบัติที่สำคัญของการเปลี่ยนแปลงที่นำมาใช้ในการโค่นล้ม 1.7 คือการรวมศูนย์ของที่เก็บข้อมูลเมทาดาทางานที่คัดลอกไว้ในที่เดียว แทนที่จะเป็น.svnไดเรกทอรีในทุกไดเรกทอรีในสำเนาการทำงาน Subversion 1.7 สำเนาการทำงานมีเพียง.svnไดเรกทอรีเดียว- ในรากของสำเนาการทำงาน ไดเรกทอรีนี้รวมถึง (เหนือสิ่งอื่นใด) ฐานข้อมูล SQLite ที่สำรองไว้ซึ่งมีความต้องการการโค่นล้มข้อมูลเมตาทั้งหมดสำหรับสำเนาการทำงานนั้น


4
เพื่อประสิทธิภาพลองใช้find ... -print0 | xargs -0 egrep ...แทนfind ... -exec grep ...(ไม่แยกgrepกันสำหรับแต่ละไฟล์ แต่สำหรับแต่ละไฟล์ในเวลาเดียวกัน) ใช้แบบฟอร์มนี้คุณยังสามารถตัด.svnไดเรกทอรีโดยไม่ใช้-pruneตัวเลือกของการค้นหาเช่นfind ... -print0 | egrep -v '/\.svn' | xargs -0 egrep ...
vladr

3
@ วลาด: เท่าที่ฉันรู้การใช้-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 '{}' '+'.
Siu Ching Pong-Asuka Kenji-

2
@ วลาด: นอกจากนี้การgrepออกนอกบ้าน.svnก็ไม่ใช่ความคิดที่ดีเช่นกัน ในขณะที่findมีความเชี่ยวชาญในการจัดการคุณสมบัติไฟล์grepไม่ ในตัวอย่างของคุณไฟล์ชื่อ'.svn.txt'จะถูกกรองโดยegrepคำสั่งของคุณ แม้ว่าคุณสามารถปรับเปลี่ยน regex ของคุณเป็น'^ / \. svn $' ได้แต่ก็ยังไม่เป็นเช่นนั้น เพรดิเคต-pruneของการfindทำงานอย่างสมบูรณ์แบบสำหรับการกรองไฟล์ (ตามชื่อไฟล์หรือเวลาการสร้างหรือเงื่อนไขใด ๆ ที่คุณให้ไว้) มันก็เหมือนกับแม้ว่าคุณจะสามารถฆ่าแมลงสาบด้วยดาบขนาดใหญ่ไม่ได้หมายความว่ามันเป็นวิธีที่แนะนำให้ทำ :-)
งุดชิงโปง - อะซึกะเคนจิ -

3
การสลับไปใช้ Git แก้ไขปัญหานี้ (รวมถึงอื่น ๆ อีกมากมาย) ในทำให้โฟลเดอร์. git เท่านั้นบนรูทของสำเนาการทำงานไม่ใช่ในทุก ๆ โฟลเดอร์ของมันเช่น SVN นอกจากนี้โฟลเดอร์. git ไม่มีไฟล์ธรรมดาที่อาจสับสนกับไฟล์จริงของคุณด้วยชื่อเดียวกัน
Tronic

3
2Dan Molding: svn 1.7 สร้างไดเรกทอรี. svn ระดับบนสุดเพียงครั้งเดียว
ccpizza

คำตอบ:


65

สำหรับการค้นหาฉันขอแนะนำให้คุณดูackหรือไม่? เป็นการรับรู้ซอร์สโค้ดfindและจะละเว้นไฟล์หลายประเภทโดยอัตโนมัติรวมถึงข้อมูลที่เก็บซอร์สโค้ดเช่นด้านบน


3
ฉันชอบackมาก แต่ฉันพบว่ามันช้ากว่าfind -type f -name "*.[ch]" | xargs grepเมื่อต้องรับมือกับ codebase ขนาดใหญ่
John Ledbetter

63
จอห์นฉันเป็นผู้เขียน ack และถ้าคุณสามารถให้รายละเอียดเกี่ยวกับปัญหาความเร็วของ ack กับ grep ฉันจะขอบคุณมัน พวกเขาเปรียบเทียบได้อย่างสมบูรณ์ในทุกกรณีที่ฉันพบ โปรดแจ้งให้เราทราบที่github.com/petdance/ack/issuesหรือส่งอีเมลถึงฉันที่ andy ที่ petdance.com Thansk
Andy Lester

63
Guys นั่นเป็นคำแนะนำ แต่แน่นอนว่าไม่ใช่คำตอบสำหรับคำถาม! :)
dolzenko

8
จะไม่ถูกackเรียกเก็บเงินที่ดีกว่าgrepไม่ได้เป็นแหล่งที่มาทราบfind? ตัวอย่างบางส่วนของการใช้มันเพื่อแทนที่จะfindทำให้นี่เป็นคำตอบที่แท้จริง
michiakig

3
มันเป็นคำตอบสำหรับคำถามที่เขาไม่รู้ว่าเขาถาม =)
Frungi

293

ทำไมไม่เพียงแค่

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

- ไม่ใช่เพรดิเคต negates ทุกอย่างที่มี. svn ที่ใดก็ได้ในเส้นทาง

ดังนั้นในกรณีของคุณมันจะเป็น

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

5
+1 ยิ่งใหญ่สุดสำหรับ "-not" และ "-iwholename" Ack เป็นสิ่งที่ยอดเยี่ยมและฉันใช้มัน แต่ find / exec ยังคงมีประโยชน์อยู่
David Blevins

9
คำตอบเดียวที่ตอบคำถามเดิมจริง ๆ
Brendon Crawford

14
ฉันแยกออกจากองค์ประกอบของฉันและฉันแน่ใจว่าฉันจะได้รับการวิพากษ์วิจารณ์สำหรับความคิดเห็นนี้ แต่เห็นได้ชัดว่า -not และ -wholename ไม่สอดคล้องกับ POSIX ฉันใช้ ! แทนที่ -not และ -path แทนที่ -iwholename และได้ผลลัพธ์เดียวกัน ตาม man page ของฉัน (Ubuntu 12.04) ไวยากรณ์นี้สอดคล้องกับ POSIX
จอห์น

1
@whaley คุณบอกว่า'*.svn*'ในตอนแรก '*.svn'แต่แล้ว อะไรถูก ทำงานทั้งคู่หรือไม่ ฉันคิดว่ามันน่าจะเป็น '*.svn*'อย่างไร
Keith M

1
@ KeithM จับได้ดีจริง ๆ คำตอบนี้นั่งอยู่ที่นี่มาหลายปีแล้วและฉันไม่คิดว่าจะมีใครจับได้จนถึงตอนนี้
Whaley

141

ดังนี้

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

หรืออีกทางหนึ่งขึ้นอยู่กับไดเรกทอรีและไม่ใช่คำนำหน้าเส้นทาง:

find . -name .svn -a -type d -prune -o -print

14
@Kaleb: สวัสดี ฉันแนะนำfind . -type d -name .svn -prune -o -printเพราะมันเร็วกว่านิดหน่อย ตามมาตรฐาน POSIXนิพจน์จะได้รับการประเมินทีละรายการตามลำดับที่ระบุ หากการแสดงออกครั้งแรกใน-aคือfalseการแสดงออกที่สองจะไม่ได้รับการประเมิน (เรียกว่าลัดวงจรและการประเมินผล )
งุดชิงโปง - อะซึกะเคนจิ -

2
@Kaleb: การเปรียบเทียบประเภทไฟล์ (เทียบเท่ากับการทดสอบว่าบิตถูกตั้งค่าเป็นจำนวนเต็ม) นั้นเร็วกว่าการเปรียบเทียบชื่อไฟล์ (เทียบเท่ากับการเปรียบเทียบสตริงซึ่งเป็น O (n)) การวาง-type dก่อนหน้า-name .svnนี้มีประสิทธิภาพมากกว่าในทางทฤษฎี อย่างไรก็ตามมันมักจะไม่สำคัญยกเว้นถ้าคุณมีต้นไม้ไดเรกทอรีที่ใหญ่มาก
งุดชิงโปง - อาสึกะเคนจิ -

5
@ SiuChingPong-AsukaKenji- ไม่การเปรียบเทียบเฉพาะชื่อไฟล์นั้นเร็วขึ้นเพราะ -type ต้องการการเรียก stat (2) ในทุก ๆ ไฟล์ ชื่อไฟล์อย่างไรก็ตามเป็นส่วนหนึ่งของการตอบสนอง readdir (3)
hraban

3
@JonathanHartley คุณไม่มี-printส่วนร่วมในการแสดงออกครั้งสุดท้าย สิ่งที่ชอบfind . -name .git -prune -o \( -type f -name LICENSE -print \)ทำงานตามที่คาดไว้
sschuberth

1
หากคุณต้องการที่จะไม่สนใจทั้ง .git และ .svn find . -name .svn -prune -o -name .git -prune -o -type d -printและเพียงรายการไดเรกทอรีอื่น มันอาจจะเป็นเวลาไม่กี่มิลลิวินาทีในการวาง-type dก่อนที่ทั้งสองจะเร็วกว่า-nameแต่ก็ไม่คุ้มกับการพิมพ์เพิ่มเติม
JPaget

34

ที่จะไม่สนใจ.svn, .gitและไดเรกทอรีที่ซ่อนอยู่อื่น ๆ (เริ่มต้นด้วยจุด) ลอง:

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

อย่างไรก็ตามหากจุดประสงค์ของการใช้findคือค้นหาภายในไฟล์คุณอาจลองใช้คำสั่งเหล่านี้:

  • git grep - คำสั่งที่ออกแบบมาเป็นพิเศษสำหรับการค้นหารูปแบบภายในที่เก็บ Git
  • ripgrep- .gitignoreซึ่งโดยละเว้นเริ่มต้นไฟล์ที่ซ่อนอยู่และไฟล์ที่ระบุไว้ใน

ที่เกี่ยวข้อง: ฉันจะค้นหาไฟล์ทั้งหมดที่มีข้อความเฉพาะบน Linux ได้อย่างไร


คำตอบที่ดีที่สุด คนอื่นพยายามอธิบายสิ่งต่าง ๆ ที่ไม่ตอบคำถามง่าย ๆ
แอนโทนี่

19

นี่คือสิ่งที่ฉันจะทำในกรณีของคุณ:

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รูปแบบสำหรับปัญหาเฉพาะของคุณ


12

GNU ค้นหา

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

ฉันกำลังโหลดเส้นทางไดเรกทอรีลงในอาร์เรย์เพื่อให้ PHP ประมวลผล คำตอบอื่น ๆ ที่สูงขึ้น (ด้วยเหตุผลใดก็ตาม) ไม่ได้กรองไฟล์ในการค้นหา (แม้จะมี-type d) - คำตอบนี้ทำ +1
จะ hollenbeck

11

ฉันใช้ 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 ใช้ตัวเลือกเหล่านี้โดยอัตโนมัติในการเรียกใช้


1
เป็นที่น่าสังเกตว่า 'grep' ได้รับตัวเลือก '--exclude-dir' เพียงหนึ่งปีหรือสองปีที่แล้ว ลีนุกซ์ลีนุกซ์รุ่นล่าสุดนั้นมี แต่ถ้าฉันจำได้อย่างถูกต้องฉันต้องรวบรวม grep ของตัวเอง (หรือขอให้ homebrew ทำ) บน OSX
Jonathan Hartley

ฉันใช้ตัวแปรย่อยนี้ .bashrc ฉันสร้างฟังก์ชั่นทุบตี 'GRP' GREP_OPTIONS=xxx grep "$@"ซึ่งถูกกำหนดให้เป็น ซึ่งหมายความว่าตัวแปร GREP_OPTIONS ถูกตั้งค่าสำหรับอินสแตนซ์ของ grep ที่ฉันเรียกใช้ด้วยตนเองโดยใช้ 'grp' นี่หมายความว่าฉันไม่เคยได้รับสถานการณ์ที่ฉันเรียกใช้เครื่องมือและภายในเรียกว่า grep แต่เครื่องมือจะสับสนเพราะ grep ไม่ทำงานตามที่คาดไว้ นอกจากนี้ฉันมีฟังก์ชั่นที่สอง 'grpy' ซึ่งเรียกว่า 'grp' แต่เพิ่ม--include=*.pyเข้าไปเพื่อค้นหาไฟล์ Python
Jonathan Hartley

ที่จริงแล้วในการไตร่ตรองทำในแบบของฉันไม่จำเป็นต้องใช้ GREP_OPTIONS อีกเลย ตอนนี้ฉันเพิ่งมีฟังก์ชันเชลล์ 'grp' ที่เรียกgrep --exclude=tags --exclude_dir=.git ...etc... "$@"ใช้ ฉันชอบสิ่งนี้ที่เรียกว่า 'ack' แต่ฉันยังคงรับรู้และควบคุมสิ่งที่มันทำอยู่
Jonathan Hartley

9

find . | grep -v \.svn


คุณต้องหลบหนี.ใน.svnregexp
vladr

4
ใช้--fixed-stringsด้วย grep: | fgrep -v /.svn/หรือ `| grep -F -v / .svn / `เพื่อแยกไดเรกทอรีอย่างแน่นอนและไม่ใช่ไฟล์ที่มี" .svn "เป็นส่วนหนึ่งของชื่อ
สตีเฟ่น P

8

ทำไมคุณไม่ไพพ์คำสั่งด้วย grep ซึ่งเข้าใจได้ง่าย:

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

คุณต้องหลบหนี.ใน.svnregexp
vladr

@ Yclian โดยไม่ต้องสงสัยเงา; หากคุณไม่ทำเช่นนั้นไดเรกทอรีที่เรียกว่า 'tsvn', '1svn', 'asvn' เป็นต้นจะถูกละเว้นตั้งแต่ '' เป็นสัญลักษณ์แทน regexp: 'จับคู่อักขระใด ๆ '
vladr

เอาล่ะฉันคิดว่ามันจะเกิดขึ้นสำหรับกรณีของ -E และ -G เท่านั้น ฉันเพิ่งทดสอบไม่ดีของฉัน :(
yclian

2
ฉันชอบคำตอบนี้เพราะมันเป็นแนวคิดที่ง่ายกว่าคนอื่นทั้งหมด ฉันไม่สามารถจำไวยากรณ์ที่น่าหัวเราะสำหรับการใช้งาน 'find' แต่ฉันสามารถจำวิธีใช้ grep -v ได้อย่างแน่นอนเนื่องจากมันถูกใช้ในหลาย ๆ สถานการณ์
mattismyname

8

สร้างสคริปต์ที่เรียกว่า~/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;

สคริปต์นี้ไม่ทำงานอย่างที่ฉันคาดไว้ เมื่อรันด้วย "svnfind -type f" มันยังพิมพ์ svn-directory และไฟล์ใน svn-directory ด้วย
Ingo Fischer

@ifischer คุณสามารถเพิ่มechoคำสั่ง find และบอกฉันว่าคำสั่งใดที่ถูกเรียกใช้งาน? svnfind -type fใช้งานได้ดีกับเครื่อง Red Hat ของฉัน
John Kugelman

ตกลงดังนั้นดูเหมือนว่าจะขึ้นอยู่กับระบบปฏิบัติการ ฉันใช้ Debian Squeeze (เหมือนกันบน Ubuntu) ฉันไม่เข้าใจความหมายของคำว่า "เพิ่มเสียงสะท้อน"
Ingo Fischer

@ifischer เปลี่ยนบรรทัดสุดท้ายecho find "${OPTIONS[@]}"...เป็นคำสั่ง find พิมพ์แทนการรันจริง
John Kugelman

Ok เปลี่ยนบรรทัดสุดท้ายเป็นecho find ${OPTIONS[@]} ${PATHS[@]} -name .svn -type d -prune -o ( ${EXPR[@]} ) $ACTIONนี่ให้ผลลัพธ์ต่อไปนี้:find -type f -name .svn -type d -prune -o ( -true ) -print
Ingo Fischer

5

แค่คิดว่าฉันจะเพิ่มทางเลือกง่าย ๆที่จะ Kaleb และโพสต์ของผู้อื่น (ซึ่งมีรายละเอียดการใช้งานของfind -pruneตัวเลือกack, repofindคำสั่ง ฯลฯ ) ซึ่งเป็นโดยเฉพาะอย่างยิ่งที่ใช้บังคับกับการใช้งานที่คุณได้อธิบายไว้ในคำถาม (และประเพณีที่คล้ายกันอื่น ๆ ):

  1. เพื่อประสิทธิภาพที่คุณควรพยายามที่จะใช้find ... -exec grep ... +(ขอบคุณเคนจิสำหรับการชี้ออกมานี้) หรือ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's -pruneตรรกะ.)

    find | grep | xargsวิธีการคล้ายกับ GNU find's -regexตัวเลือก (ดูghostdog74โพสต์) แต่เป็นแบบพกพามากขึ้น (ยังจะทำงานบนแพลตฟอร์มที่ GNU findไม่สามารถใช้ได้.)


1
@Vlad: แจ้งให้ทราบล่วงหน้ากรุณาว่ามีสองรูปแบบสำหรับ-execสวิทช์ในfindหนึ่งกำลังจะสิ้นสุดลงด้วย;และอื่น ๆ +ที่ลงท้ายด้วย ไฟล์เดียวที่ลงท้ายด้วย+แทนที่{}ด้วยรายการไฟล์ที่ตรงกันทั้งหมด นอกจากนี้ regex ของคุณจะ'/\.svn'จับคู่ชื่อไฟล์เช่น'.svn.txt'กัน โปรดอ้างอิงถึงความคิดเห็นของฉันสำหรับคำถามสำหรับข้อมูลเพิ่มเติม
Siu Ching Pong-Asuka Kenji-

2
@Vlad: นี่คือมาตรฐาน POSIX สำหรับfindยูทิลิตี้ โปรดดู-execส่วน :-)
งุดชิงโปง - อะซึกะเคนจิ -

4

ในที่เก็บซอร์สโค้ดโดยทั่วไปฉันต้องการทำสิ่งต่าง ๆ กับไฟล์ข้อความเท่านั้น

บรรทัดแรกคือไฟล์ทั้งหมดยกเว้นไฟล์ที่เก็บ 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


3

ในการแก้ไขปัญหานี้คุณสามารถใช้เงื่อนไขการค้นหานี้:

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


3

ทราบว่าถ้าคุณทำ

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

จากนั้น-printจะบอกเป็นนัยเมื่อนิพจน์ทั้งหมด ( -type f -name 'messages.*') เป็นจริงเพราะไม่มี 'การกระทำ' (เช่น-exec)

ในขณะที่หากต้องการหยุดการลดระดับลงในไดเรกทอรีบางรายการคุณควรใช้สิ่งที่ตรงกับไดเรกทอรีเหล่านั้นและปฏิบัติตามโดย-prune(ซึ่งมีวัตถุประสงค์เพื่อหยุดการลดระดับลงในไดเรกทอรี); ชอบมาก:

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

สิ่งนี้จะประเมินเป็นTrueสำหรับไดเรกทอรี. svn และเราสามารถใช้บูลีนลัดวงจรโดยทำตามนี้โดย-o(OR) หลังจากนั้นสิ่งที่ตามมาหลังจากนั้น-oจะถูกตรวจสอบเฉพาะเมื่อส่วนแรกเป็นเท็จดังนั้นจึงไม่ใช่ไดเรกทอรี. svn ในคำอื่น ๆ ต่อไปนี้:

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

จะประเมินเฉพาะสิ่งที่ถูกต้อง-oเท่านั้นคือ-name 'message.*' -exec grep -Iw uint {}สำหรับไฟล์ที่ไม่อยู่ในไดเรกทอรี. svn

โปรดทราบว่าเนื่องจาก.svnอาจเป็นไดเรกทอรี (และไม่ใช่ตัวอย่างไฟล์) เสมอและในกรณีนี้แน่นอนไม่ตรงกับชื่อ 'ข้อความ *' คุณอาจต้องละทิ้ง-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


2

ลองใช้findrepoซึ่งเป็น wrapper ง่าย ๆ ในการค้นหา / grep และเร็วกว่า ack มากคุณจะใช้มันในกรณีนี้เช่น:

findrepo uint 'messages.*'


1

สิ่งนี้ใช้ได้กับฉันใน Unix prompt

gfind \ (-not -wholename '* \. svn *' \) ข้อความ -type f -name '. *' -exec grep -Iw uint {} +

คำสั่งด้านบนจะแสดงรายการไฟล์ที่ไม่ได้อยู่ใน. svn และทำ grep ที่คุณกล่าวถึง


'gfind' เป็นตัวพิมพ์ใหญ่หรือไม่ ฉันไม่มีใน Ubuntu 14.04
Jonathan Hartley

สมมติว่าคุณหมายถึง 'ค้นหา' สิ่งนี้ไม่ได้ผล xxx.svnxxxนอกจากนี้ยังกรองเอาไฟล์เช่น สิ่งนี้สำคัญ - ตัวอย่างเช่นหากคุณใช้ git แทนที่จะเป็น svn คุณมักจะต้องการรวมไฟล์เช่น. gitignore (ซึ่งไม่ใช่ข้อมูลเมตาเป็นไฟล์ปกติที่รวมอยู่ใน repo) ในผลลัพธ์จาก find
Jonathan Hartley

1

ฉันมักจะส่งออกท่อผ่าน grep อีกครั้งหนึ่งเอา. svn ในการใช้งานของฉันมันไม่ได้ช้ากว่ามาก ตัวอย่างทั่วไป:

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

หรือ

find . -type f -print0 | xargs -0 egrep messages. | grep -Ev '.svn|.git|.anythingElseIwannaIgnore'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.