ค้นหา: ลูกพรุนไม่สนใจเส้นทางที่ระบุ


13

ฉันต้องแยก.gitออกจากการfindค้นหาของฉัน เพื่อให้บรรลุผลนั้นฉันใช้-path ./.git -pruneสวิตช์:

$ find . -path ./.git -prune -o \( -type f -o -type l -o -type d \) | grep '.git'
./.git

อย่างไรก็ตามแม้ว่าสิ่งนี้จะข้ามเนื้อหาของไดเรกทอรี. git แต่จะแสดงรายการไดเรกทอรีเอง มันทำงานได้เมื่อฉันเพิ่ม-path ./.git -prune -o -print -a

find . -path ./.git -prune -o -print -a \( -type f -o -type l -o -type d \) | grep '.git'

ทำไมถึงมีความจำเป็น ฉันคิดว่าทั้งสองคำสั่งควรมีเอาต์พุตเหมือนกัน ไวยากรณ์ที่สองค่อนข้างน่าเกลียด


4
คุณต้องการ a -printมิฉะนั้นนัย-printจะใช้กับเงื่อนไขทั้งหมด
Stéphane Chazelas

1
ดูเพิ่มเติมที่unix.stackexchange.com/q/102191/22565
Stéphane Chazelas

คำตอบ:


3

manหน้าfindให้:

-prune True; if the file is a directory, do not  descend  into  it.  If
      -depth  is  given,  false;  no  effect.  Because -delete implies
      -depth, you cannot usefully use -prune and -delete together.

ดังนั้นในตัวอย่างแรกมันไม่เป็นเช่นนั้น-path ./.git -pruneจริงและดังนั้นการกระทำเริ่มต้น ( -print) จะไม่ถูกเรียกดังนั้นจึงมีการพิมพ์บรรทัด


22

ฉันสับสนว่าเหตุใดไดเรกทอรีที่ถูกตัดออกถูกพิมพ์โดยfindคำสั่งด้วยและรายละเอียดที่ซับซ้อนอื่น ๆ เกี่ยวกับวิธีการ-pruneทำงาน แต่ก็สามารถเข้าใจได้ด้วยตัวอย่างบางส่วน

หากต้องการเรียกใช้ตัวอย่างด้านล่างให้สร้างไดเรกทอรีและไฟล์ต่อไปนี้

mkdir aa
mkdir bb
touch file1
touch aa/file1
touch bb/file3

ในการสร้างโครงสร้างนี้:

$ tree

.
├── aa
   └── file1
├── bb
   └── file3
└── file1

aaตอนนี้ใช้หาที่จะมองหาไดเรกทอรีที่มีชื่อ ไม่มีปัญหาที่นี่

$ find . -type d -name aa
./aa

ค้นหาไดเรกทอรีทั้งหมดนอกเหนือจาก aa และเราได้รับไดเรกทอรีปัจจุบัน.และ./bbซึ่งก็สมเหตุสมผล

$ find . -type d ! -name aa
.
./bb

จนถึงตอนนี้ดีมาก แต่เมื่อเราใช้งาน-prunefind จะคืนค่าไดเรกทอรีที่เรากำลังตัดซึ่งตอนแรกทำให้ฉันสับสนเพราะฉันคาดว่ามันจะส่งคืนไดเรกทอรีอื่นทั้งหมดและไม่ใช่ไดเรกทอรีที่ถูกตัด

$ find . -type d -name aa -prune
./aa

เหตุผลที่ส่งคืนไดเร็กทอรีที่ถูกตัดจะไม่อธิบายใน-pruneส่วนของ man pages ดังที่ระบุไว้ในคำตอบของ Timoแต่ในEXPRESSIONSหัวข้อ:

หากการแสดงออกมีการกระทำอื่น ๆ กว่าไม่-prune,  -printจะดำเนินการเกี่ยวกับไฟล์ทั้งหมดที่แสดงออกเป็นความจริง

ซึ่งหมายความว่าเนื่องจากการแสดงออกที่ตรงกับaaชื่อไดเรกทอรีแล้วการแสดงออกจะประเมินเป็นจริงและมันจะถูกพิมพ์เพราะการค้นหาเพิ่มโดยปริยาย-printที่ท้ายคำสั่งทั้งหมด อย่างไรก็ตามจะไม่เพิ่มก-printหากคุณตั้งใจเพิ่มการกระทำ-o -printลงไปในตอนท้ายด้วยตนเอง:

find . -type d -name aa -prune -o -print
.
./file1
./bb
./bb/file3

ที่นี่คำสั่ง find ไม่เพิ่มความหมาย-printอีกต่อไปดังนั้นไดเรกทอรีที่เราตัด ( aa) จะไม่ถูกพิมพ์

ดังนั้นในที่สุดหากเราเพิ่มส่วนคำสั่งที่ค้นหาไฟล์ที่มีรูปแบบชื่อไฟล์file*หลังจาก-oนั้นคุณจะต้องวาง-printส่วนท้ายของส่วนคำสั่งที่สองดังนี้:

find . \( -type d -name aa -prune \) -o \( -type f -name 'file*' -print \)
./file1
./bb/file3

เหตุผลที่ทำให้การทำงานเหมือนกัน: ถ้าคุณไม่ใส่-printประโยคที่สองลงไปเนื่องจากไม่มีการกระทำใดนอกเหนือจาก-pruneการกระทำการค้นหาจะเพิ่ม-printคำสั่งโดยอัตโนมัติเมื่อสิ้นสุดคำสั่งทำให้-pruneคำสั่งพิมพ์ ไดเร็กทอรีที่ถูกตัดทิ้ง:

find . \( \( -type d -name aa -prune \) -o \( -type f -name 'file*' \) \) -print
./aa
./file1
./bb/file3

โดยทั่วไปคุณต้องวาง-printคำสั่งในประโยคที่สอง หากคุณวางไว้ตรงกลางเหมือนโปสเตอร์ต้นฉบับมันจะไม่ทำงานอย่างถูกต้องเพราะไฟล์ที่ถูกตัดจะถูกพิมพ์ทันทีและประโยคที่สองจะไม่ได้รับโอกาสในการเลือกไฟล์ที่ต้องการ:

find . \( -type d -name aa -prune -o -print \) -o \( -type f -name 'file*' \)
.
./file1
./bb
./bb/file3

น่าเสียดายที่โปสเตอร์ต้นฉบับนั้นได้รับคำสั่งที่ผิดด้านบนโดยการวาง-printในตำแหน่งที่ผิด อาจใช้กับกรณีเฉพาะของเขา แต่ไม่สามารถใช้งานได้ในกรณีทั่วไป

มีคนหลายพันคนที่มีปัญหาในการเข้าใจวิธีการ-pruneทำงาน findหน้าคนควรได้รับการปรับปรุงเพื่อป้องกันความสับสนทั่วโลก neverending เกี่ยวกับคำสั่งนี้


หน้าคนของฉัน (Arch Linux, find-4.6.0) กล่าวว่า "หากนิพจน์ทั้งหมดไม่มีการดำเนินการอื่นนอกเหนือจาก -prune หรือ -print, -print จะถูกดำเนินการกับไฟล์ทั้งหมดที่นิพจน์ทั้งหมดเป็นจริง" แต่ทำงานตามที่คุณอธิบาย
x-yuri

0

จากmanหน้า

หากต้องการละเว้นแผนผังไดเร็กทอรีทั้งหมดให้ใช้ -prune แทนการตรวจสอบทุกไฟล์ในแผนผัง ตัวอย่างเช่นในการข้ามไดเรกทอรี `src / emacs 'และทุกไฟล์และไดเรกทอรีภายใต้มันและพิมพ์ชื่อของไฟล์อื่น ๆ ที่พบทำสิ่งนี้:

find . -path ./src/emacs -prune -o -print

ดังนั้นคุณอาจใช้:

find . -path ./.git -prune -o -print

นี่จะไม่แสดงรายการ.gitไดเรกทอรี

หากต้องการระบุชื่อไฟล์คุณสามารถทำสิ่งนี้ได้:

find . -path ./.git -prune , -name filename

โปรดสังเกต,ผู้ประกอบการจุลภาค


-1

นี่เป็นทางเลือกที่รวดเร็วและสกปรก:

find | fgrep -v /.git

ฉันจำfindไวยากรณ์ที่ซับซ้อนของจำไม่ได้...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.