วิธีแยกไดเรกทอรีในการค้นหา คำสั่ง


1380

ฉันพยายามเรียกใช้findคำสั่งสำหรับไฟล์ JavaScript ทั้งหมด แต่ฉันจะแยกไดเรกทอรีเฉพาะได้อย่างไร

นี่คือfindรหัสที่เราใช้

for file in $(find . -name '*.js')
do 
  java -jar config/yuicompressor-2.4.2.jar --type js $file -o $file
done

10
ไดเรกทอรีที่คุณต้องแยกคืออะไร
เทพพอล

11
find ... | while read -r file ...ดีกว่าที่จะใช้ นอกจากนี้ยังเป็นการดีกว่าที่จะยอมรับและยกเลิกคำตอบ
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

ในขณะที่การอ่านช้าสำหรับในเร็ว
mpapis

18
@mpapis ในขณะที่อ่านอย่างถูกต้องจัดการเต็มบรรทัดด้วยช่องว่าง
Jean-Philippe Pellet

1
for file in $(find .); do echo "$file"; doneเพียงแค่เรียกใช้ในโฟลเดอร์ที่มีไฟล์ที่มีช่องว่างในชื่อของพวกเขา: ชื่อที่มีช่องว่างแยกออกซึ่งเราไม่ต้องการ
Jean-Philippe Pellet

คำตอบ:


1140

ใช้-pruneสวิตช์ ตัวอย่างเช่นหากคุณต้องการยกเว้นmiscไดเรกทอรีเพียงเพิ่ม-path ./misc -prune -oคำสั่ง find ของคุณ:

find . -path ./misc -prune -o -name '*.txt' -print

นี่คือตัวอย่างที่มีหลายไดเรกทอรี:

find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print

ที่นี่เราไม่รวมdir1 , dir2และdir3ตั้งแต่ในfindการแสดงออกมันคือการกระทำที่ทำหน้าที่อยู่กับเกณฑ์ที่-path dir1 -o -path dir2 -o -path dir3(ถ้าdir1หรือdir2หรือdir3 ) ANDed type -dกับ

การดำเนินการเพิ่มเติมคือ-o printเพียงพิมพ์


89
อืมมม สิ่งนี้ไม่ได้ผลสำหรับฉันอย่างใดอย่างหนึ่งเนื่องจากจะรวมไดเรกทอรีที่ถูกละเว้น "./misc" ในผลลัพธ์
Theuni

84
@Theuni มันอาจไม่ได้ผลสำหรับคุณเพราะคุณไม่ได้เพิ่ม-print(หรือการกระทำอื่น ๆ ) อย่างชัดเจนหลังจาก-nameนั้น ในกรณีนั้นทั้งสอง "ด้าน" ของ-oการพิมพ์ท้ายในขณะที่ถ้าคุณใช้-printเฉพาะด้านที่พิมพ์
Daniel C. Sobral

4
จาก manpage: Because -delete implies -depth, you cannot usefully use -prune and -delete together.ฉันจะลบการค้นหาได้อย่างไรถ้าฉันต้องการแยกไดเรกทอรีที่เฉพาะเจาะจงออกจากการลบ?
Jānis Elmeris

15
ในการลบไดเรกทอรีทั้งหมดออกจากผลลัพธ์ให้ใช้: find . -not -path "./.git*". การใช้./dir*แทนการ./dir/*ลบไดเรกทอรีรวมถึงเนื้อหาจากผลลัพธ์
micahblu

64
คำถามนี้และความสับสนในคำตอบนั้นเป็นสิ่งที่แสดงให้เห็นว่าอินเทอร์เฟซผู้ใช้ค้นหาไม่ตรงกับสิ่งที่ผู้คนต้องการมากแค่ไหน
Johannes Overmann

1931

หาก-pruneไม่ได้ผลสำหรับคุณสิ่งนี้จะ:

find -name "*.js" -not -path "./directory/*"

Caveat:ต้องผ่านไดเรกทอรีที่ไม่ต้องการทั้งหมด


86
หนึ่งในความคิดเห็นในคำตอบที่ยอมรับนั้นชี้ให้เห็นปัญหา -pruneไม่ได้แยกไดเรกทอรีตัวเองมันไม่รวมเนื้อหาของมันซึ่งหมายความว่าคุณจะได้รับบรรทัดที่ไม่พึงประสงค์ในการส่งออกที่มีไดเรกทอรีที่ถูกแยกออก
ฟรี

95
คำตอบที่ดี ฉันต้องการเพิ่มไปนี้ที่คุณสามารถยกเว้นไดเรกทอรีในระดับใดโดยการเปลี่ยนคนแรกที่ไป. *ดังนั้นfind -name "*.js" -not -path "*/omitme/*"จะละเว้นไฟล์จากไดเรกทอรีชื่อ "omitme" ที่ระดับความลึกใด ๆ
DeeDee

83
มันยังคงข้ามไดเรกทอรีที่ไม่พึงประสงค์ทั้งหมด ฉันกำลังเพิ่มคำตอบของฉันเอง :-)
Daniel C. Sobral

18
อย่างไรก็ตามโปรดทราบว่าตัวเลือกพรุนไม่ทำงานหากคุณไม่ได้ใช้-printอย่างชัดเจน
Daniel C. Sobral

39
มันจะเป็นการดีกว่าถ้าจะพูดว่า "นี่เป็นทางเลือกสำหรับการใช้ -prune" คำตอบที่บอกว่า -prune นั้นไม่ผิดเลยมันไม่ใช่วิธีที่คุณจะทำ
Jimbo

458

ฉันพบเหตุผลต่อไปนี้ง่ายกว่าโซลูชันที่เสนออื่น ๆ :

find build -not \( -path build/external -prune \) -name \*.js
# you can also exclude multiple paths
find build -not \( -path build/external -prune \) -not \( -path build/blog -prune \) -name \*.js

หมายเหตุสำคัญ:เส้นทางที่คุณพิมพ์หลังจากนั้น-pathจะต้องตรงกับสิ่งที่findจะพิมพ์โดยไม่มีการยกเว้น ถ้าประโยคนี้ทำให้คุณงงคุณต้องแน่ใจว่าใช้เส้นทางแบบเต็มตลอดทั้งคำสั่งเช่นนี้: . ดูหมายเหตุ [1] หากคุณต้องการความเข้าใจที่ดีขึ้นfind /full/path/ -not \( -path /full/path/exclude/this -prune \) ...

ภายใน\(และ\)คือการแสดงออกที่จะตรงตรง build/external (ดูหมายเหตุสำคัญดังกล่าวข้างต้น) และจะในความสำเร็จหลีกเลี่ยง traversing อะไรด้านล่าง นี่คือการจัดกลุ่มเป็นนิพจน์เดียวกับวงเล็บที่มีการยกเว้นและนำหน้าด้วย-notซึ่งจะทำให้findข้ามสิ่งที่จับคู่กับนิพจน์นั้น

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

สิ่งนี้มาจากกรณีการใช้งานจริงที่ฉันต้องการเรียก yui-compressor บนไฟล์บางไฟล์ที่สร้างโดย wintersmith แต่ปล่อยให้ไฟล์อื่น ๆ ที่ต้องส่งตามที่เป็นอยู่


หมายเหตุ [1] : ถ้าคุณต้องการที่จะแยกออก/tmp/foo/barและคุณเรียกหาเช่นนี้ " find /tmp \(..." -path /tmp/foo/barแล้วคุณจะต้องระบุ ถ้าในขณะที่คุณใช้ค้นหาเช่นนี้แล้วคุณจะต้องระบุcd /tmp; find . \(...-path ./foo/bar


37
คำตอบที่โดดเด่นขอบคุณ ใช้งานได้และสามารถปรับขนาดได้ (อ่านได้) สำหรับการยกเว้นหลายรายการ คุณเป็นสุภาพบุรุษและเป็นนักวิชาการ ขอบคุณสำหรับตัวอย่างสำหรับการยกเว้นหลายรายการ
Freedom_Ben

7
สิ่งนี้ใช้ไม่ได้หากฉันต้องการใช้ -delete switch:find . -not \( -path ./CVS -prune \) -type f -mtime +100 -delete find: The -delete action atomatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.
Jānis Elmeris

17
@Janis คุณสามารถใช้แทน-exec rm -rf {} \; -delete
Daniel C. Sobral

11
โดยการตรวจสอบผลลัพธ์ของfindสิ่งนี้ชัดเจนจริงๆ แต่ทำให้ผมสะดุด ถ้าคุณกำลังค้นหาในไดเรกทอรีปัจจุบัน (โดยระบุ.เป็นเส้นทางการค้นหาหรือไม่ได้ระบุอย่างใดอย่างหนึ่งที่ทุกคน) คุณน่าจะต้องการรูปแบบของคุณหลังจากที่-pathเริ่มต้นด้วยเช่น:./ find -not \( -path ./.git -prune \) -type f
Zantier

7
รูปแบบที่แม่นยำยิ่งขึ้น (และเข้ากันได้กับ POSIX) ของวิธีนี้: find searchdir \! \( -type d \( -path './excludedir/*' -o -path './excludedir2/*' -o -path './excludedir3/*' \) -prune \)ตามด้วยเงื่อนไขใด ๆ ที่ควรตรงกับสิ่งที่คุณกำลังมองหา
Walf

217

เห็นได้ชัดว่ามีความสับสนบางอย่างที่นี่เป็นสิ่งที่ไวยากรณ์ที่ต้องการสำหรับการข้ามไดเรกทอรีควร

ความเห็นของ GNU

To ignore a directory and the files under it, use -prune

จาก GNU ค้นหาหน้าคน

เหตุผล

-pruneหยุดfindจากมากไปน้อยในไดเรกทอรี เพียงแค่การระบุ-not -pathจะยังคงลงมาในไดเรกทอรีที่ข้ามแต่-not -pathจะเป็นเท็จทุกfindครั้งที่ทดสอบแต่ละไฟล์

ปัญหาเกี่ยวกับ -prune

-prune ทำสิ่งที่ตั้งใจจะทำ แต่ก็ยังมีบางสิ่งที่คุณต้องดูแลเมื่อใช้งาน

  1. find พิมพ์ไดเร็กทอรีที่ตัดแล้ว

    • TRUEนั่นเป็นพฤติกรรมที่ตั้งใจ แต่มันไม่ได้ลงมา หากต้องการหลีกเลี่ยงการพิมพ์ไดเรกทอรีทั้งหมดให้ใช้ไวยากรณ์ที่เว้นไว้อย่างมีเหตุผล
  2. -pruneใช้งานได้เฉพาะกับ-printและไม่มีการกระทำอื่น

    • ไม่เป็นความจริง -pruneทำงานร่วมกับการกระทำใด ๆ -deleteยกเว้น เหตุใดจึงไม่ทำงานกับการลบ สำหรับ-deleteการทำงานให้ค้นหาความต้องการที่จะสำรวจไดเรกทอรีในลำดับ DFS ตั้งแต่-deleteแรกจะลบใบจากนั้นผู้ปกครองของใบ ฯลฯ ... แต่สำหรับการระบุ-pruneให้เหมาะสมfindต้องตีไดเรกทอรีและหยุดลงมันซึ่ง ชัดเจนไม่มีเหตุผลกับ-depthหรือ-deleteใน

ประสิทธิภาพ

ฉันตั้งค่าการทดสอบง่าย ๆ ของสามคำตอบ upvote บนคำถามนี้ (แทนที่-printด้วย-exec bash -c 'echo $0' {} \;เพื่อแสดงตัวอย่างการกระทำอื่น) ผลลัพธ์อยู่ด้านล่าง

----------------------------------------------
# of files/dirs in level one directories
.performance_test/prune_me     702702    
.performance_test/other        2         
----------------------------------------------

> find ".performance_test" -path ".performance_test/prune_me" -prune -o -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 23513814

> find ".performance_test" -not \( -path ".performance_test/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 10670141

> find ".performance_test" -not -path ".performance_test/prune_me*" -exec bash -c 'echo "$0"' {} \;
.performance_test
.performance_test/other
.performance_test/other/foo
  [# of files] 3 [Runtime(ns)] 864843145

ข้อสรุป

ทั้งไวยากรณ์ของ f10bitและไวยากรณ์ของDaniel C. Sobralใช้เวลา 10-25ms ในการทำงานโดยเฉลี่ย ไวยากรณ์ของ GetFreeซึ่งไม่ได้ใช้จะใช้-pruneเวลา 865 มิลลิวินาที ดังนั้นใช่นี้เป็นตัวอย่างที่ค่อนข้างมาก -pruneแต่ถ้าคุณดูแลเกี่ยวกับเวลาทำงานและกำลังทำสิ่งที่ไกลเข้มข้นที่คุณควรใช้

หมายเหตุ: ไวยากรณ์ของ Daniel C. Sobral ทำงานได้ดีขึ้นในสอง-pruneไวยากรณ์ แต่ฉันสงสัยอย่างมากว่านี่เป็นผลมาจากการแคชบางอย่างในขณะที่เปลี่ยนลำดับที่ทั้งสองวิ่งทำให้เกิดผลลัพธ์ตรงกันข้ามในขณะที่เวอร์ชันที่ไม่ใช่ลูกพรุนนั้นช้าที่สุดเสมอ

สคริปต์ทดสอบ

#!/bin/bash

dir='.performance_test'

setup() {
  mkdir "$dir" || exit 1
  mkdir -p "$dir/prune_me/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/w/x/y/z" \
    "$dir/other"

  find "$dir/prune_me" -depth -type d -exec mkdir '{}'/{A..Z} \;
  find "$dir/prune_me" -type d -exec touch '{}'/{1..1000} \;
  touch "$dir/other/foo"
}

cleanup() {
  rm -rf "$dir"
}

stats() {
  for file in "$dir"/*; do
    if [[ -d "$file" ]]; then
      count=$(find "$file" | wc -l)
      printf "%-30s %-10s\n" "$file" "$count"
    fi
  done
}

name1() {
  find "$dir" -path "$dir/prune_me" -prune -o -exec bash -c 'echo "$0"'  {} \;
}

name2() {
  find "$dir" -not \( -path "$dir/prune_me" -prune \) -exec bash -c 'echo "$0"' {} \;
}

name3() {
  find "$dir" -not -path "$dir/prune_me*" -exec bash -c 'echo "$0"' {} \;
}

printf "Setting up test files...\n\n"
setup
echo "----------------------------------------------"
echo "# of files/dirs in level one directories"
stats | sort -k 2 -n -r
echo "----------------------------------------------"

printf "\nRunning performance test...\n\n"

echo \> find \""$dir"\" -path \""$dir/prune_me"\" -prune -o -exec bash -c \'echo \"\$0\"\'  {} \\\;
name1
s=$(date +%s%N)
name1_num=$(name1 | wc -l)
e=$(date +%s%N)
name1_perf=$((e-s))
printf "  [# of files] $name1_num [Runtime(ns)] $name1_perf\n\n"

echo \> find \""$dir"\" -not \\\( -path \""$dir/prune_me"\" -prune \\\) -exec bash -c \'echo \"\$0\"\' {} \\\;
name2
s=$(date +%s%N)
name2_num=$(name2 | wc -l)
e=$(date +%s%N)
name2_perf=$((e-s))
printf "  [# of files] $name2_num [Runtime(ns)] $name2_perf\n\n"

echo \> find \""$dir"\" -not -path \""$dir/prune_me*"\" -exec bash -c \'echo \"\$0\"\' {} \\\;
name3
s=$(date +%s%N)
name3_num=$(name3 | wc -l)
e=$(date +%s%N)
name3_perf=$((e-s))
printf "  [# of files] $name3_num [Runtime(ns)] $name3_perf\n\n"

echo "Cleaning up test files..."
cleanup

18
ขอบคุณสำหรับการวิเคราะห์ที่ดีมาก เกี่ยวกับ "ฉันสงสัยอย่างยิ่งว่านี่เป็นผลลัพธ์ของการแคช" คุณสามารถเรียกใช้คำสั่งนี้: sudo sh -c "free && sync && echo 3> / proc / sys / vm / drop_caches && ฟรี" เพื่อล้างแคช (ดูunix stackexchange.com/questions/87908/… )
ndemou

หลังจากการทดสอบสองสามครั้งกับ-pruneฉันฉันสามารถบอกได้ว่าไม่ค่อยมีความแตกต่างใด ๆ โปรดทราบว่าคำสั่งที่เริ่มต้นครั้งแรกจะได้รับประโยชน์จากประสิทธิภาพของซีพียูในภายหลังซีพียูอุ่นเครื่อง> ประสิทธิภาพการทำงานลดลงทำให้เกิดการชะลอตัวเล็กน้อย (ฉันได้ทำการล้างแคชก่อนแต่ละคำสั่งตามคำแนะนำ @ndemou)
Huy.PhamNhu

ลองเปลี่ยนหมายเลขname1() name2() name3()ในสคริปต์การทดสอบ @BroSlow ด้านบนเพื่อเปลี่ยนคำสั่งเพื่อให้ได้ภาพเกี่ยวกับสิ่งที่ฉันพูด ในชีวิตจริงมันไม่สามารถสังเกตเห็นได้ระหว่างสองคนนี้
Huy.PhamNhu

การปรบมือ ขอบคุณสำหรับคำตอบที่มีคุณภาพนี้
Stphane

คุณไม่ควรเป็น -o ซึ่งหมายถึงหรือ ดังนั้นคุณจะตัดแต่งกิ่งในขั้นตอนแรกแล้วลืมทุกอย่างในขั้นตอนถัดไป
mmm

96

นี่เป็นคนเดียวที่ทำงานให้ฉัน

find / -name MyFile ! -path '*/Directory/*'

ค้นหา "MyFile" ไม่รวม "ไดเรกทอรี" ให้ความสำคัญกับดาว *


13
วิธีนี้ใช้ได้กับ macOS ในขณะที่คำตอบที่ยอมรับไม่ได้ ฉันรู้ว่าคำถามเดิมสำหรับ Linux
Xavier Rubio Jansana

5
โปรดทราบว่าคุณสามารถเพิ่มหลายรายการ! -path '*/Directory/*'ในคำสั่งของคุณอย่างต่อเนื่องเพื่อข้ามไดเรกทอรีหลายรายการ
Aclwitt

ใช้งานได้กับ MacOS แต่ไม่ได้ใช้กับ linux ... ยืนยันแล้ว
Marcello de Sales

ใช้docker containerงานได้เฉพาะกับsh -c "find..."
Marcello de Sales

@ Marcello de Sales แน่นอนว่ามันใช้ได้กับ Linux
DimiDak

59

ทางเลือกหนึ่งคือการแยกผลลัพธ์ทั้งหมดที่มีชื่อไดเรกทอรีด้วย grep ตัวอย่างเช่น:

find . -name '*.js' | grep -v excludeddir

44
สิ่งนี้จะทำให้การค้นหาของคุณช้ามาก
Dorian

6
อันนี้ใช้ได้กับฉันคนอื่น ๆ (ที่ใช้-prune) - ไม่
Andron

7
ช้าในผลลัพธ์ที่มีขนาดใหญ่ แต่มีประโยชน์ในชุดที่เล็กกว่า แต่จะแยกไดเรกทอรีหลายรายการโดยใช้ grep ได้อย่างไร แน่นอนด้วยวิธีนี้: find . -name '*.js' | grep -v excludeddir | grep -v excludedir2 | grep -v excludedir3แต่อาจมีวิธี grep อย่างใดอย่างหนึ่ง
Timo Kähkönen

6
หากคุณต้องการที่จะดำเนินการ greps egrep -v '(dir1|dir2|dir3)'หลายแล้วคุณจะดีกว่าการเขียนมันเป็นนิพจน์ทั่วไป: อย่างไรก็ตามในกรณีศึกษาเฉพาะนี้จะเป็นการดีกว่าที่จะยกเว้นไดเรกทอรีภายในfindตัวเอง
ลอเรนซ์

1
ใช่และคุณไม่จำเป็นต้องใช้วงเล็บและควรใช้ ^ เพื่อให้แน่ใจว่าตรงกับชื่อไดเรกทอรีที่จุดเริ่มต้นของสตริงเช่น: find -name '* .js' | egrep -v "^ \ ./ excluseddir1 | ^ \ ./ludeddir2"
Sofija

41

ฉันชอบ-notสัญกรณ์ ... อ่านง่ายกว่า:

find . -name '*.js' -and -not -path directory

5
ขออภัยมันไม่ทำงาน man page สำหรับfindพูดว่า: "หากต้องการละเว้นไดเร็กทอรีและไฟล์ที่อยู่ข้างใต้ให้ใช้ -prune"
Christian Davén

8
นี่เป็นสิ่งที่ผิด ไม่ได้ป้องกันการค้นหาไม่ให้เข้าไปในไดเรกทอรีและสำรวจไฟล์ทั้งหมดที่อยู่ภายใน
ฟรี

find . -iname '*' -and -not -path './somePath'ไม่ป้องกันไม่ให้ใส่ไดเรกทอรีดังกล่าว
Lemmings19

สิ่งนี้ช่วยฉันในเส้นทาง. git find . -iname '*' -not -path './.git/*'
Mark Shust ที่ M.academy

7
@rane: โดยเฉพาะเจาะจงมากขึ้นfind . -not -path "*/.git*"จะเป็นสิ่งที่คุณต้องการ
เบ็น

20

ใช้ตัวเลือก -prune ดังนั้นสิ่งที่ชอบ:

find . -type d -name proc -prune -o -name '*.js'

'-type d -name proc -prune' ค้นหาไดเรกทอรีที่ชื่อ proc เท่านั้นที่จะยกเว้น
'-o' เป็นตัวดำเนินการ 'OR'


1
นี่เป็นทางออกเดียวที่ "บริสุทธิ์" ที่เหมาะกับฉัน ไดเรกทอรีที่ฉันต้องการยกเว้นไม่ได้อยู่ใต้ไดเรกทอรีการทำงานปัจจุบันทันที
Lambart

5
อย่างไรก็ตามการเพิ่ม-printไปยังจุดสิ้นสุดอาจปรับปรุงผลลัพธ์ find . -type d -name .hg -prune -o -name dataละเว้นเนื้อหาของ.hgไดเรกทอรี(หลายรายการ) แต่แสดงรายการ.hgไดเรกทอรีเอง ด้วย-printจะแสดงเฉพาะไดเรกทอรี "ข้อมูล" ที่ฉันค้นหา
Lambart

19

-pruneใช้งานได้จริงและเป็นคำตอบที่ดีที่สุดเพราะจะป้องกันไม่ให้ลงไปใน dir ที่คุณต้องการยกเว้น -not -pathซึ่งยังคงค้นหา dir ที่ถูกแยกออกไปมันจะไม่พิมพ์ผลลัพธ์ซึ่งอาจเป็นปัญหาหาก dir ที่แยกออกนั้นถูกเมานต์วอลุ่มเครือข่ายหรือคุณไม่ได้รับอนุญาต

ส่วนที่ยุ่งยากนั้นfindมีความเฉพาะเจาะจงมากเกี่ยวกับลำดับของการขัดแย้งดังนั้นหากคุณไม่เข้าใจถูกต้องคำสั่งของคุณอาจไม่ทำงาน ลำดับของการขัดแย้งโดยทั่วไปเป็นเช่นนี้:

find {path} {options} {action}

{path}: ใส่อาร์กิวเมนต์ที่เกี่ยวข้องกับพา ธ ทั้งหมดก่อนเช่น . -path './dir1' -prune -o

{options}: ฉันประสบความสำเร็จมากที่สุดเมื่อวางตัว-name, -iname, etcเลือกสุดท้ายในกลุ่มนี้ เช่น-type f -iname '*.js'

{action}: คุณจะต้องเพิ่ม-printเมื่อใช้-prune

นี่คือตัวอย่างการทำงาน:

# setup test
mkdir dir1 dir2 dir3
touch dir1/file.txt; touch dir1/file.js
touch dir2/file.txt; touch dir2/file.js
touch dir3/file.txt; touch dir3/file.js

# search for *.js, exclude dir1
find . -path './dir1' -prune -o -type f -iname '*.js' -print

# search for *.js, exclude dir1 and dir2
find . \( -path './dir1' -o -path './dir2' \) -prune -o -type f -iname '*.js' -print

16

นี่คือรูปแบบที่ฉันใช้เพื่อยกเว้นบางเส้นทาง:

$ find ./ -type f -name "pattern" ! -path "excluded path" ! -path "excluded path"

ฉันใช้สิ่งนี้เพื่อค้นหาไฟล์ทั้งหมดที่ไม่ได้อยู่ในพา ธ ". *":

$ find ./ -type f -name "*" ! -path "./.*" ! -path "./*/.*"

ฉันลองสิ่งนี้และมันยังคงสืบทอดมาในไดเรกทอรีดังนั้นความเร็วจึงไม่ได้รับการปรับปรุงอย่างแน่นอน
Br.Bill

10

วิธี -path -prune ยังทำงานกับ wildcards ในพา ธ นี่คือคำสั่ง find ที่จะค้นหาไดเรกทอรีสำหรับเซิร์ฟเวอร์ git ที่ให้บริการหลาย ๆ แหล่งที่เก็บ git โดยปล่อยให้ไดเรกทอรีภายในของ git:

find . -type d \
   -not \( -path */objects -prune \) \
   -not \( -path */branches -prune \) \
   -not \( -path */refs -prune \) \
   -not \( -path */logs -prune \) \
   -not \( -path */.git -prune \) \
   -not \( -path */info -prune \) \
   -not \( -path */hooks -prune \)  

9

หากต้องการยกเว้นหลายไดเรกทอรี:

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" \)

ในการเพิ่มไดเรกทอรีให้เพิ่ม-o -path "./dirname/*":

find . -name '*.js' -not \( -path "./dir1" -o -path "./dir2/*" -o -path "./dir3/*"\)

แต่บางทีคุณควรใช้นิพจน์ทั่วไปหากมีไดเรกทอรีจำนวนมากที่จะแยกออก


9

มีคำตอบที่ดีมากมายมันใช้เวลาพอสมควรที่จะเข้าใจว่าแต่ละองค์ประกอบของคำสั่งนั้นมีอะไรและตรรกะที่อยู่เบื้องหลัง

find . -path ./misc -prune -o -name '*.txt' -print

find .หาจะเริ่มต้นการค้นหาไฟล์และไดเรกทอรีในไดเรกทอรีปัจจุบันจึง

-oตัวเลือกที่ย่อมาจากตรรกะหรือและแยกสองส่วนของคำสั่ง:

[ -path ./misc -prune ] OR [ -name '*.txt' -print ]

ไดเรกทอรีใด ๆ หรือแฟ้มที่อยู่ไม่ไดเรกทอรี ./misc -path ./miscจะไม่ผ่านการทดสอบครั้งแรก แต่พวกเขาจะถูกทดสอบกับการแสดงออกครั้งที่สอง หากชื่อของพวกเขาตรงกับรูปแบบที่*.txtพวกเขาได้รับการพิมพ์เพราะ-printตัวเลือก

เมื่อพบถึงไดเร็กทอรี. /misc ไดเร็กทอรีนี้จะตอบสนองนิพจน์แรกเท่านั้น ดังนั้น-pruneตัวเลือกจะถูกนำไปใช้กับมัน มันบอกให้คำสั่ง find ไม่สำรวจไดเร็กทอรีนั้น ดังนั้นไฟล์หรือไดเรกทอรีใด ๆ ใน. /misc จะไม่ถูกสำรวจโดย find จะไม่ถูกทดสอบเทียบกับส่วนที่สองของนิพจน์และจะไม่ถูกพิมพ์


ทุกคนมีทางออก แต่คุณอธิบายได้ดีที่สุด ฉันยืนกรานที่จะใช้ชื่อก่อนไม่ใช่ -path คำอธิบายของคุณเพียงพอที่จะไปถึงสิ่งที่ฉันต้องการ หา -name "* .txt" -print -o -path ./misc -prune
Vendetta V

7

สำหรับวิธีการทำงาน (ทดสอบบน Ubuntu 12.04 (Precise Pangolin)) ...

find ! -path "dir1" -iname "*.mp3"

จะค้นหาไฟล์ MP3 ในโฟลเดอร์ปัจจุบันและโฟลเดอร์ย่อยยกเว้นในโฟลเดอร์ย่อย dir1

ใช้:

find ! -path "dir1" ! -path "dir2" -iname "*.mp3"

... เพื่อยกเว้น dir1 AND dir2


ไม่ได้ผลสำหรับฉัน ไม่ทำคำตอบใด ๆ ข้างต้น หมวกสีแดง.
Tharpa

6

เคล็ดลับที่ดีสำหรับการหลีกเลี่ยงการพิมพ์ไดเรกทอรี pruned คือการใช้งาน-print(ผลงาน-execเช่นกัน) หลังจากที่ทางด้านขวาของหลัง-or -pruneตัวอย่างเช่น, ...

find . -path "*/.*" -prune -or -iname "*.j2"

จะพิมพ์เส้นทางของไฟล์ทั้งหมดที่อยู่ภายใต้ไดเรกทอรีปัจจุบันที่มีนามสกุล `.j2" โดยข้ามไดเรกทอรีที่ซ่อนไว้ทั้งหมดเรียบร้อย แต่ก็จะพิมพ์เส้นทางแบบเต็มของแต่ละไดเรกทอรีหนึ่งที่ข้ามไปตามที่ระบุไว้ข้างต้นอย่างไรก็ตาม การติดตามไม่ได้ ...

find . -path "*/.*" -prune -or -iname "*.j2" -print

เพราะเหตุผลมันมีที่ซ่อนอยู่-andหลังจาก-inameผู้ประกอบการและก่อนที่จะพิมพ์ สิ่งนี้จะผูกมันไว้ที่ส่วนด้านขวาของ-orประโยคเนื่องจากคำสั่งบูลีนของการดำเนินการและการเชื่อมโยง แต่เอกสารบอกว่ามีการซ่อน-printหาก-print0ไม่ได้ระบุ(หรือลูกพี่ลูกน้อง ... ฯลฯ ) เหตุใดจึงไม่เหลือส่วนที่เหลือของการ-orพิมพ์ เห็นได้ชัดว่า (และฉันไม่เข้าใจสิ่งนี้จากการอ่านหน้าแรกของฉัน) นั่นเป็นความจริงหากไม่มีการดำเนินการของรูปแบบในประโยคใด ๆ ตรรกะที่ซ่อนอยู่ทั้งหมดจะหายไปและคุณจะได้รับเฉพาะสิ่งที่คุณระบุ ตอนนี้ตรงไปตรงมาฉันอาจจะชอบวิธีอื่น ๆ รอบ ๆ แต่จากนั้น-printหรือ-execไม่ว่าที่ใดในกรณีนี้ - พิมพ์ถูกโปรยอย่างมีเหตุมีผลเช่นนั้นทุกอย่างจะถูกพิมพ์ หากแม้แต่วันเดียวprintfindผู้ประกอบการที่มีคำอธิบายเพียงอย่างเดียวจะไม่ทำอะไรเลยดังนั้นฉันคิดว่ามันสมเหตุสมผลดี ดังกล่าวข้างต้นทั้งหมดนี้ทำงานได้-execดีเช่นกันดังนั้นรายการต่อไปนี้ให้ls -laรายชื่อเต็มสำหรับแต่ละไฟล์ที่มีนามสกุลที่ต้องการ แต่ไม่แสดงรายการระดับแรกของแต่ละไดเรกทอรีที่ซ่อนอยู่ ...

find . -path "*/.*" -prune -or -iname "*.j2" -exec ls -la -- {} +

สำหรับฉัน (และคนอื่น ๆ ในชุดข้อความนี้) findไวยากรณ์จะได้รับความพิสดารค่อนข้างเร็วดังนั้นฉันจึงโยน parens เสมอเพื่อให้แน่ใจว่าฉันรู้ว่าอะไรที่ผูกกับอะไรดังนั้นฉันมักจะสร้างแมโครสำหรับความสามารถในการพิมพ์ ..

find . \( \( ... description of stuff to avoid ... \) -prune \) -or \
\( ... description of stuff I want to find ... [ -exec or -print] \)

เป็นการยากที่จะผิดไปโดยตั้งโลกเป็นสองส่วนด้วยวิธีนี้ ฉันหวังว่านี่จะช่วยได้ แต่ดูเหมือนว่าทุกคนจะไม่ได้อ่านคำตอบที่ 30+ และลงคะแนน แต่ก็มีใครหวังได้ :-)


5

คุณสามารถใช้ตัวเลือกพรุนเพื่อให้บรรลุนี้ เช่นในตัวอย่าง:

find ./ -path ./beta/* -prune -o -iname example.com -print

หรือตัวเลือก grep“ grep -v” แบบผกผัน:

find -iname example.com | grep -v beta

คุณสามารถค้นหาคำแนะนำรายละเอียดและตัวอย่างในลินุกซ์หาคำสั่งยกเว้นไดเรกทอรีจากการค้นหา


โซลูชัน grep เป็นเพียงไดเรกทอรีเดียวที่แยกไดเรกทอรีทั้งหมดด้วยชื่อเดียวกัน เมื่อพยายามที่จะแยก "node_modules" ที่ค่อนข้างมีประโยชน์
bmacnaughton

3
@bmacnaughton - ไม่เป็นความจริง! ฉันมาที่นี่โดยเฉพาะที่ต้องการแยก "node_modules" และหลังจากอ่านคำตอบที่ดีมากมายที่ฉันตัดสินfind . -type f -print -o -path "*/node_modules" -prune... ใช้สัญลักษณ์แทนการข้าม "node_modules" ที่ระดับใด การใช้-printตัวเลือกแรกนั้น-type f -printจะทำการพิมพ์เฉพาะส่วนนั้นดังนั้นไดเรกทอรี "node_modules" จะไม่ปรากฏในรายการ (ก็ยังสามารถกลับ: find . -path "*/node_modules" -prune -o -type f -print)
สตีเฟ่นพี

* / กำลังทำอะไรอยู่ที่นั่น ไฟล์ที่แน่นอนที่คุณต้องการยกเว้นคืออะไร ypu ที่ใช้มันเป็นไวด์การ์ด?
Siju V

1
@StephenP ขอบคุณสำหรับการชี้ให้เห็น; ฉันเรียนรู้ความแตกต่างระหว่างการใช้./node_modulesกับ*/node_modulesมัน สำหรับกรณีของฉันnode_modulesมีอยู่ในไดเรกทอรีที่ฉันเริ่มการค้นหาใน (และภายใต้node_modulesไดเรกทอรีนั้น) ฉันสามารถใช้find . -type f -print -o -path "./node_modules" -prune เพราะจะไม่มีnode_modulesไดเรกทอรีในไดเรกทอรีอื่น ๆ
bmacnaughton

1
@SijuV - ในไดเรกทอรีที่ฉันค้นหามีnode_modulesไดเรกทอรีย่อย แต่ก็มีไดเรกทอรีย่อยที่มีnode_modulesของตัวเอง... โดยใช้การ./node_modulesจับคู่เฉพาะไดเรกทอรีย่อยnode_modulesภายใต้ไดเรกทอรีปัจจุบัน.และตัด ใช้การ*/node_modulesจับคู่และตัดทอนไดเรกทอรีที่ระดับความลึกใด ๆ เนื่องจากใน*ฐานะที่เป็นกลมตรงกับคำนำหน้าเส้นทางชั้นนำใด ๆ เช่น./test5/main/node_modulesไม่เพียง แต่./คำนำหน้า The *wildcard แต่เป็น glob ไม่เหมือน regex
Stephen P

5
find . -name '*.js' -\! -name 'glob-for-excluded-dir' -prune

ไม่สามารถทำให้อันนี้ใช้งานได้ find ~/Projects -name '*.js' -\! -name 'node_modules' -pruneยังคงเปิดขึ้นไฟล์ที่มีnode_modulesอยู่ในเส้นทางของพวกเขา
mpen

1
@mpen จากstackoverflow.com/questions/4210042/...find ~/Projects -path ~/Projects/node_modules -prune -o -name '*.js' -printผมได้เรียนรู้ว่าไวยากรณ์ที่คุณต้องการคือ ชื่อของเส้นทางนั้นจะต้องตรงกับสิ่งที่ค้นหาจะพิมพ์หากกำลังจะพิมพ์ไดเรกทอรี
PatS

4
find -name '*.js' -not -path './node_modules/*' -not -path './vendor/*'

ดูเหมือนว่าจะทำงานเช่นเดียวกับ

find -name '*.js' -not \( -path './node_modules/*' -o -path './vendor/*' \)

และง่ายต่อการจดจำ IMO


4

TLDR:เข้าใจไดเรกทอรีรูทของคุณและปรับแต่งการค้นหาของคุณจากตรงนั้นโดยใช้-path <excluded_path> -prune -oตัวเลือก อย่ารวมส่วนท้าย/ที่ส่วนท้ายของเส้นทางที่ถูกแยก

ตัวอย่าง:

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print


เพื่อใช้อย่างมีประสิทธิภาพfindฉันเชื่อว่ามันเป็นสิ่งจำเป็นที่จะมีความเข้าใจที่ดีของโครงสร้างไดเรกทอรีระบบไฟล์ของคุณ ในคอมพิวเตอร์ที่บ้านของฉันฉันมีฮาร์ดไดรฟ์หลาย TB โดยประมาณครึ่งหนึ่งของเนื้อหานั้นสำรองโดยใช้rsnapshot(เช่นrsync) แม้ว่าจะสำรองข้อมูลไปยังไดรฟ์ (ซ้ำ) ที่เป็นอิสระทางกายภาพ แต่จะถูกเมาท์ภายใต้/ไดเรกทอรีsystem root ( ) ของฉัน/mnt/Backups/rsnapshot_backups/:

/mnt/Backups/
└── rsnapshot_backups/
    ├── hourly.0/
    ├── hourly.1/
    ├── ...
    ├── daily.0/
    ├── daily.1/
    ├── ...
    ├── weekly.0/
    ├── weekly.1/
    ├── ...
    ├── monthly.0/
    ├── monthly.1/
    └── ...

/mnt/Backups/rsnapshot_backups/ไดเรกทอรีปัจจุบันมี ~ 2.9 TB ด้วย ~ ไฟล์และโฟลเดอร์ 60M; เพียงแค่สำรวจเนื้อหาเหล่านั้นต้องใช้เวลา:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find /mnt/Backups/rsnapshot_backups | wc -l
60314138    ## 60.3M files, folders
34:07.30    ## 34 min

time du /mnt/Backups/rsnapshot_backups -d 0
3112240160  /mnt/Backups/rsnapshot_backups    ## 3.1 TB
33:51.88    ## 34 min

time rsnapshot du    ## << more accurate re: rsnapshot footprint
2.9T    /mnt/Backups/rsnapshot_backups/hourly.0/
4.1G    /mnt/Backups/rsnapshot_backups/hourly.1/
...
4.7G    /mnt/Backups/rsnapshot_backups/weekly.3/
2.9T    total    ## 2.9 TB, per sudo rsnapshot du (more accurate)
2:34:54          ## 2 hr 35 min

ดังนั้นเมื่อใดก็ตามที่ฉันต้องการค้นหาไฟล์บน/พาร์ติชั่น (root) ของฉันฉันต้องจัดการกับ (หลีกเลี่ยงถ้าเป็นไปได้) ภายในการสำรองข้อมูลพาร์ติชันของฉัน


ตัวอย่าง

ในบรรดาคำแนะนำที่ได้รับการแนะนำต่าง ๆ ในเธรดนี้ ( วิธีการแยกไดเรกทอรีในคำสั่ง find. ) ฉันพบว่าการค้นหาที่ใช้คำตอบที่ยอมรับนั้นเร็วกว่ามาก - ด้วยคำเตือน

โซลูชันที่ 1

สมมติว่าฉันต้องการค้นหาไฟล์ระบบlibname-server-2.aแต่ฉันไม่ต้องการค้นหาrsnapshotข้อมูลสำรองของฉัน หากต้องการค้นหาไฟล์ระบบอย่างรวดเร็วให้ใช้เส้นทางแยก/mnt(เช่นใช้/mntไม่ใช่/mnt/หรือ/mnt/Backupsหรือ ... ):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a
real    0m8.644s              ## 8.6 sec  <<< NOTE!
user    0m1.669s
 sys    0m2.466s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 3 sec     ## ~3 sec  <<< NOTE!

... พบไฟล์นั้นในเวลาเพียงไม่กี่วินาทีในขณะที่มันใช้เวลานานกว่ามาก (ดูเหมือนจะเรียกคืนผ่านไดเรกทอรี "ยกเว้น" ทั้งหมด):

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -path /mnt/ -prune -o -name "*libname-server-2.a*" -print
find: warning: -path /mnt/ will not match anything because it ends with /.
/usr/lib/libname-server-2.a
real    33m10.658s            ## 33 min 11 sec (~231-663x slower!)
user    1m43.142s
 sys    2m22.666s

## As regular user (victoria); I also use an alternate timing mechanism, as
## here I am using 2>/dev/null to suppress "Permission denied" warnings:

$ START="$(date +"%s")" && find 2>/dev/null / -path /mnt/ -prune -o \
    -name "*libname-server-2.a*" -print; END="$(date +"%s")"; \
    TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/usr/lib/libname-server-2.a
find command took 1775 sec    ## 29.6 min

โซลูชันที่ 2

โซลูชันอื่นที่นำเสนอในเธรดนี้ ( SO # 4210042 ) ก็ทำงานได้ไม่ดีเช่นกัน:

## As sudo (#), to avoid numerous "Permission denied" warnings:

time find / -name "*libname-server-2.a*" -not -path "/mnt"
/usr/lib/libname-server-2.a
real    33m37.911s            ## 33 min 38 sec (~235x slower)
user    1m45.134s
 sys    2m31.846s

time find / -name "*libname-server-2.a*" -not -path "/mnt/*"
/usr/lib/libname-server-2.a
real    33m11.208s            ## 33 min 11 sec
user    1m22.185s
 sys    2m29.962s

สรุป สรุป

ใช้วิธีการที่แสดงใน " โซลูชัน 1 "

find / -path /mnt -prune -o -name "*libname-server-2.a*" -print

กล่าวคือ

... -path <excluded_path> -prune -o ...

สังเกตว่าเมื่อใดก็ตามที่คุณเพิ่มการติดตาม/ลงในพา ธ ที่แยกออกfindคำสั่งนั้นจะเข้าสู่/mnt/*ไดเรกทอรี(ทั้งหมดเหล่านั้น) ซ้ำ- ซึ่งในกรณีของฉันเนื่องจาก/mnt/Backups/rsnapshot_backups/*ไดเรกทอรีย่อยรวมถึงไฟล์ที่จะค้นหา ~ 2.9 TB! โดยไม่ผนวกท้าย/การค้นหาควรจะเสร็จสมบูรณ์เกือบจะในทันที (ภายในไม่กี่วินาที)

"โซลูชัน 2" ( ... -not -path <exclude path> ...) เช่นเดียวกันดูเหมือนจะค้นหาซ้ำในไดเรกทอรีที่แยกออก - ไม่ส่งคืนการจับคู่ที่ยกเว้น แต่กลับใช้เวลาค้นหานั้นโดยไม่จำเป็น


ค้นหาภายในrsnapshotข้อมูลสำรองเหล่านั้น:

หากต้องการค้นหาไฟล์ในการrsnapshotสำรองข้อมูลรายชั่วโมง / รายวัน / รายสัปดาห์ / รายเดือนของฉัน):

$ START="$(date +"%s")" && find 2>/dev/null /mnt/Backups/rsnapshot_backups/daily.0 -name '*04t8ugijrlkj.jpg'; END="$(date +"%s")"; TIME="$((END - START))"; printf 'find command took %s sec\n' "$TIME"
/mnt/Backups/rsnapshot_backups/daily.0/snapshot_root/mnt/Vancouver/temp/04t8ugijrlkj.jpg
find command took 312 sec   ## 5.2 minutes: despite apparent rsnapshot size
                            ## (~4 GB), it is in fact searching through ~2.9 TB)

การแยกไดเรกทอรีที่ซ้อนกัน:

ที่นี่ฉันต้องการยกเว้นไดเรกทอรีที่ซ้อนกันเช่น/mnt/Vancouver/projects/ie/claws/data/*เมื่อค้นหาจาก/mnt/Vancouver/projects/:

$ time find . -iname '*test_file*'
./ie/claws/data/test_file
./ie/claws/test_file
0:01.97

$ time find . -path '*/data' -prune -o -iname '*test_file*' -print
./ie/claws/test_file
0:00.07

นอกเหนือ: การเพิ่ม-printที่ส่วนท้ายของคำสั่งจะไม่แสดงผลการพิมพ์ของไดเรกทอรีที่ถูกแยกออก:

$ find / -path /mnt -prune -o -name "*libname-server-2.a*"
/mnt
/usr/lib/libname-server-2.a

$ find / -path /mnt -prune -o -name "*libname-server-2.a*" -print
/usr/lib/libname-server-2.a

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

@TobySpeight: จุดดี ฉันพูดถึงขนาดพื้นที่ค้นหาเพื่อระบุมาตราส่วนซึ่งยังมีไฟล์จำนวนมาก การค้นหาอย่างรวดเร็วของรูท (/) พร้อมsudo ls -R / | wc -lไฟล์ ~ ~ ~ ~ ~ ~ ~ ~ 76.5M (ส่วนใหญ่จะทำการสำรองยกเว้นไฟล์ระบบ "non-config"); /mnt/Vancouver/ด้วยการls -R | wc -lบ่งชี้ ~ 2.35M ไฟล์; /home/victoria/มีไฟล์ 0.668M
Victoria Stuart

4

นอกจากนี้คุณยังสามารถใช้นิพจน์ทั่วไปเพื่อรวม / ยกเว้นบางไฟล์ / dirs การค้นหาของคุณโดยใช้สิ่งนี้:

find . -regextype posix-egrep -regex ".*\.(js|vue|s?css|php|html|json)$" -and -not -regex ".*/(node_modules|vendor)/.*" 

สิ่งนี้จะให้ไฟล์ js, vue, css, etc ทั้งหมดให้คุณ แต่ไม่รวมไฟล์ทั้งหมดในnode_modulesและvendorโฟลเดอร์


3

ฉันใช้findเพื่อจัดทำรายการไฟล์สำหรับxgettextและต้องการละเว้นไดเรกทอรีเฉพาะและเนื้อหา ฉันลองใช้พีชคณิต-pathร่วมกับ-pruneแต่ไม่สามารถแยกไดเรกทอรีที่ฉันต้องการได้อย่างสมบูรณ์

แม้ว่าฉันสามารถละเว้นเนื้อหาของไดเรกทอรีที่ฉันต้องการละเว้นfindจากนั้นส่งคืนไดเรกทอรีเองเป็นหนึ่งในผลลัพธ์ซึ่งทำให้xgettextความผิดพลาดเป็นผลลัพธ์ (ไม่ยอมรับไดเรกทอรีเฉพาะไฟล์)

โซลูชันของฉันคือใช้grep -vข้ามไดเรกทอรีที่ฉันไม่ต้องการในผลลัพธ์:

find /project/directory -iname '*.php' -or -iname '*.phtml' | grep -iv '/some/directory' | xargs xgettext

ไม่ว่าจะมีข้อโต้แย้งfindว่าจะได้ผล 100% ฉันไม่สามารถพูดได้อย่างแน่นอน การใช้grepเป็นวิธีแก้ปัญหาที่ง่ายและรวดเร็วหลังจากปวดหัว


3

ไม่มีคำตอบก่อนหน้านี้ที่ดีใน Ubuntu ลองสิ่งนี้:

find . ! -path "*/test/*" -type f -name "*.js" ! -name "*-min-*" ! -name "*console*"

ฉันได้พบสิ่งนี้ที่นี่


ฉันไม่เห็นเหตุผลใด ๆ ว่าทำไมคำตอบใด ๆ ที่มีมากกว่า 100 คะแนนไม่ควรใช้กับ Ubuntu
Axel Beckert

mmm มาดูกันไหม? อาจเป็นเพราะฉันลองทั้งหมดของพวกเขา?
sixro

find มีอยู่ทุกที่ที่มีการใช้งานเหมือนกันในลีนุกซ์ดิสทริบิวชั่น - จากโครงการ GNU ความแตกต่างเพียงอย่างเดียวอาจเป็นรุ่น แต่การเปลี่ยนแปลงในทศวรรษที่ผ่านมาไม่ได้เป็นการรุกรานเว้นแต่อาจเป็นการจับคู่ที่ได้รับอนุญาต
Axel Beckert

3

สิ่งนี้เหมาะสำหรับฉันใน Mac:

find . -name *.php -or -path "./vendor" -prune -or -path "./app/cache" -prune

มันจะไม่รวมvendorและapp/cachedir สำหรับชื่อค้นหาที่phpต่อท้ายด้วย


ใส่เครื่องหมายคำพูดเดี่ยวรอบ '* .php' ดีกว่าหรือคุณจะไม่พบสิ่งที่ต้องการ
Br.Bill

3

สำหรับผู้ที่ใช้ UNIX เวอร์ชันเก่าที่ไม่สามารถใช้-pathหรือ-not

ทดสอบกับ SunOS 5.10 bash 3.2 และ SunOS 5.11 bash 4.4

find . -type f -name "*" -o -type d -name "*excluded_directory*" -prune -type f

สามารถส่งผ่านมากกว่าไดเรกทอรีที่ระบุ
MUY เบลเยี่ยม

2

วิธีใช้ลูกพรุนตัวเลือกในการค้นหาเป็นคำตอบที่ยอดเยี่ยมโดยLaurence Gonsalvesเกี่ยวกับวิธีการ-pruneทำงาน

และนี่คือคำตอบทั่วไป:

find /path/to/search                    \
  -type d                               \
    \( -path /path/to/search/exclude_me \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print

หากต้องการหลีกเลี่ยงการพิมพ์/path/to/seach/หลาย ๆ ครั้งให้ห่อfindเป็นpushd .. popdคู่

pushd /path/to/search;                  \
find .                                  \
  -type d                               \
    \( -path ./exclude_me               \
       -o                               \
       -name exclude_me_too_anywhere    \
     \)                                 \
    -prune                              \
  -o                                    \
  -type f -name '*\.js' -print;         \
 popd

1
จากstackoverflow.com/questions/4210042/ …ฉันได้เรียนรู้ว่าไวยากรณ์ที่ใช้สำหรับ-pathต้องตรงกับชื่อที่ค้นหาจะพิมพ์หากต้องพิมพ์ไดเรกทอรีดังนั้นตัวอย่างเช่น find . -path ./.git -prune -o -printหรือ find $HOME/foo -path $HOME/foo/.git -prune -o -print คำตอบบางคำพูด-path somedirที่น่าเสียดาย ไม่แน่นอนพอที่จะเป็นประโยชน์
PatS

2

สำหรับสิ่งที่ฉันต้องการมันใช้งานได้เช่นนี้การค้นหาlandscape.jpgในเซิร์ฟเวอร์ทั้งหมดเริ่มต้นจากรูทและไม่รวมการค้นหาใน/varไดเรกทอรี:

find / -maxdepth 1 -type d | grep -v /var | xargs -I '{}' find '{}' -name landscape.jpg

find / -maxdepth 1 -type dแสดงรายการทั้งหมดd irectories ใน/

grep -v /var แยก `/ var 'ออกจากรายการ

xargs -I '{}' find '{}' -name landscape.jpgรันคำสั่งใด ๆ เช่นเดียวfindกับแต่ละไดเรกทอรี / ผลจากรายการ


รอสักครู่/ยังไม่รวม sed 1dคุณอาจต้อง
สิงโต

2

คำสั่งต่อไปนี้ใช้งานได้:

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

หากคุณมีปัญหากับการค้นหาให้ใช้-D treeตัวเลือกเพื่อดูข้อมูลการวิเคราะห์นิพจน์

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

หรือ-D allเพื่อดูข้อมูลการดำเนินการทั้งหมด

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

1

ฉันพบชื่อฟังก์ชั่นในไฟล์ต้นฉบับ C ไม่รวม * .o และแยก * .swp และยกเว้น (ไม่ใช่ไฟล์ปกติ) และไม่รวมเอาต์พุต dir ด้วยคำสั่งนี้:

find .  \( ! -path "./output/*" \) -a \( -type f \) -a \( ! -name '*.o' \) -a \( ! -name '*.swp' \) | xargs grep -n soc_attach

1

ใช้การexecกระทำได้ดีกว่าการforวนซ้ำ:

find . -path "./dirtoexclude" -prune \
    -o -exec java -jar config/yuicompressor-2.4.2.jar --type js '{}' -o '{}' \;

exec ... '{}' ... '{}' \;จะถูกดำเนินการครั้งเดียวสำหรับไฟล์ที่ตรงกันทุกแทนวงเล็บ'{}'ด้วยชื่อไฟล์ปัจจุบัน

ขอให้สังเกตว่าการจัดฟันจะถูกปิดล้อมอยู่ในเครื่องหมายคำพูดเดียวที่จะปกป้องพวกเขาจากการตีความเป็นเครื่องหมายวรรคตอนเชลล์สคริปต์*


หมายเหตุ

*จากส่วนตัวอย่างของfind (GNU findutils) 4.4.2หน้าคน


1
คำถามเก่ามาก แต่ยังมีพื้นที่สำหรับการปรับปรุง ฉันพบโดยบังเอิญพยายามแก้ปัญหาที่คล้ายกันและไม่มีคำตอบใดที่น่าพอใจ
Alberto

ฉันใช้การexecกระทำนี้บ่อยครั้งและพบว่ามีประโยชน์มาก ฉันมักจะเพิ่มคำพูดระหว่างในกรณีที่มีช่องว่างในเส้นทางแฟ้มที่ให้{} "{}"
Ludovic Kuty

@ lkuty ฉันกำลังจะแก้ไขโพสต์ของฉันเพื่อสะท้อนความคิดเห็นของคุณ แต่หลังจากการทดสอบอย่างรวดเร็ว (โดยไม่ต้องอ้างอิง{}จะทำงานกับไฟล์ที่มี whitespaces ในชื่อของพวกเขา) และดูในหน้า man ดูเหมือนว่า quoting จำเป็นเท่านั้นที่จะหลีกเลี่ยง พวกเขาจะตีความผิดเป็นเครื่องหมายวรรคตอนเชลล์สคริปต์ ในกรณีนี้คุณจะใช้ข้อความเดี่ยว:'{}'
Alberto

ผมคิดว่าผมต้องใช้มันเพื่อให้cpหรือหรือmv rmฉันจะตรวจสอบออก
Ludovic Kuty

1

ฉันลองใช้คำสั่งด้านบน แต่ไม่มีผู้ใดที่ใช้ "-prune" ได้ผลสำหรับฉัน ในที่สุดฉันก็ลองใช้คำสั่งด้านล่าง:

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