วิธีแยก / เพิกเฉยไฟล์และไดเรกทอรีที่ซ่อนอยู่ในการค้นหา“ ค้นหา” ที่มีสัญลักษณ์ไวด์การ์ดฝังอยู่แล้ว?


119

เริ่มต้นจาก (สังเกตสัญลักษณ์แทนก่อนและหลัง "ข้อความบางส่วน")

find . -type f -name '*some text*'

วิธีหนึ่งสามารถแยก / ละเว้นไฟล์และไดเรกทอรีที่ซ่อนอยู่ทั้งหมดได้อย่างไร

ฉันได้ทำGoogle นานเกินไปแล้วเจอ -prune และ! พารามิเตอร์ (เครื่องหมายอัศเจรีย์) แต่ไม่มีตัวอย่างการปรับ (และการสรุป) ที่เหมาะสม

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

ป.ล. : ค้นหาไฟล์ใน linux และแยกไดเรกทอรีเฉพาะดูเหมือนว่ามีความสัมพันธ์กัน แต่ก) ยังไม่ได้รับการยอมรับและ b) เกี่ยวข้อง แต่แตกต่างกันและแตกต่างกัน แต่ c) อาจเป็นแรงบันดาลใจและช่วยระบุความสับสน!

แก้ไข

find . \( ! -regex '.*/\..*' \) -type f -name "whatever"ทำงาน regex จะมองหา "อะไรก็ตามจากนั้นเครื่องหมายทับแล้วจุดแล้วก็อะไรก็ได้" (เช่นไฟล์และโฟลเดอร์ที่ซ่อนอยู่ทั้งหมดรวมถึงโฟลเดอร์ย่อย) และ "!" ขัดแย้งกับ regex


ไม่ช่วยสิ่งที่คุณถามในการแก้ไขของคุณ แต่ลองดูคำถามของฉันและคำตอบที่นี่: unix.stackexchange.com/q/69164/15760และลิงก์ในคำตอบ

คำตอบ:


134

สิ่งนี้จะพิมพ์ไฟล์ทั้งหมดที่เป็นลูกหลานของไดเรกทอรีของคุณโดยข้ามไฟล์และไดเรกทอรีที่ซ่อนอยู่:

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

ดังนั้นหากคุณกำลังมองหาไฟล์ที่มีsome textชื่ออยู่และคุณต้องการข้ามไฟล์และไดเรกทอรีที่ซ่อนอยู่ให้รัน:

find . -not -path '*/\.*' -type f -name '*some text*'

คำอธิบาย:

-pathตัวเลือกทำงานการตรวจสอบรูปแบบกับสตริงเส้นทางทั้งหมด *เป็นสัญลักษณ์แทน/เป็นตัวคั่นไดเรกทอรี\.เป็นจุด (ต้องหลีกเลี่ยงเพื่อหลีกเลี่ยงความหมายพิเศษ) และ*เป็นสัญลักษณ์แทนอื่น -notหมายความว่าอย่าเลือกไฟล์ที่ตรงกับการทดสอบนี้

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

 find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f -name '*some text*' -print

หมายเหตุกับคนสุดท้ายที่คุณต้องการ-printในตอนท้าย! นอกจากนี้ไม่แน่ใจว่า-name '\.*' would be more efficient instead of -path (เพราะเส้นทางกำลังค้นหา subpaths แต่สิ่งเหล่านี้จะถูกตัดออก)
artfulrobot

ความหมายพิเศษของอะไร.ในบริบทนี้
frostschutz

@frostschutz จุดหลังfindหมายถึงไดเรกทอรีปัจจุบัน: findจะดูไฟล์และไดเรกทอรีทั้งหมดภายใต้ไดเรกทอรีปัจจุบัน อาร์กิวเมนต์หลังจากpathนั้นเป็นนิพจน์ทั่วไปโดยที่จุดจะหมายถึง "อักขระใด ๆ " ตามปกติเพื่อทำให้มันหมายถึงจุดตัวอักษรที่เราต้องหลบหนีด้วยแบ็กสแลช อาร์กิวเมนต์หลังจากที่-name ไม่ได้แสดงออกปกติ แต่มันขยายสัญลักษณ์เหมือน?และ*เหมือนเปลือกไม่
Flimm

2
@frostschutz ที่จริงแล้วลองคิดดูฉันอาจผิดเกี่ยวกับ.การมีความหมายพิเศษ
Flimm

1
@Flimm yup .ไม่จำเป็นที่จะหลบหนี เท่าที่ผมทราบเพียงเหล่านี้จะต้องหนี: *, และ? []
thdoan

10

นี่เป็นหนึ่งในไม่กี่วิธีในการแยกจุดไฟล์ที่ทำงานอย่างถูกต้องบน BSD, Mac และ Linux:

find "$PWD" -name ".*" -prune -o -print
  • $PWD พิมพ์พา ธ เต็มไปยังไดเร็กทอรีปัจจุบันเพื่อให้พา ธ ไม่ได้ขึ้นต้นด้วย ./
  • -name ".*" -prune ตรงกับไฟล์หรือไดเรกทอรีใด ๆ ที่ขึ้นต้นด้วยจุดแล้วไม่ต้องลงมา
  • -o -printหมายถึงพิมพ์ชื่อไฟล์หากการแสดงออกก่อนหน้านี้ไม่ตรงกับสิ่งใด การใช้-printหรือ-print0ทำให้นิพจน์อื่น ๆ ทั้งหมดไม่พิมพ์ตามค่าเริ่มต้น

โปรดอธิบาย / อธิบายอย่างละเอียดเกี่ยวกับ "ซับซ้อนอย่างน่าตกใจ"; คำตอบที่ได้รับแล้วและคำตอบของคุณดูเหมือนจะให้หลักฐานในทางตรงกันข้าม ... ?
บ๊องเกี่ยวกับ natty

2
"ซับซ้อนน่าตกใจ" น่าจะมากเกินไป ฉันใส่คำตอบใหม่เพื่อไปให้ถึงจุด ฉันคิดว่าคำตอบที่ฉันโพสต์นั้นยากที่จะเข้าใจและยากที่จะเห็นโดยไม่อ่านหน้าคู่มืออย่างระมัดระวัง หากคุณใช้ GNU เพียงค้นหาก็มีวิธีแก้ไขที่เป็นไปได้มากกว่า
eradman

-o ... -printมีประโยชน์ สำหรับการใช้งานของฉันตอนนี้ฉันมีfind ... '!' -name . -name '.*' -prune -o ... -printซึ่งสะดวกกว่าการรวม $ PWD
Roger Pate

4
find $DIR -not -path '*/\.*' -type f \( ! -iname ".*" \)

ไม่รวมไดเรกทอรีที่ซ่อนอยู่ทั้งหมดและไฟล์ที่ซ่อนอยู่ภายใต้ $ DIR


นี่คือคำตอบที่สมบูรณ์แบบ มันจะค้นหาไฟล์ทั้งหมดซ้ำ แต่ไม่รวมรายการโฆษณาสำหรับไดเรกทอรีและไฟล์ที่ซ่อนอยู่ ขอบคุณ!
KyleFarris

2

คำตอบผมเดิมเป็น "แก้ไข" ไปที่คำถามเดิมของฉันข้างต้น:

find . \( ! -regex '.*/\..*' \) -type f -name "whatever"ทำงาน regex จะมองหา "อะไรก็ตามจากนั้นเครื่องหมายทับแล้วจุดแล้วก็อะไรก็ได้" (เช่นไฟล์และโฟลเดอร์ที่ซ่อนอยู่ทั้งหมดรวมถึงโฟลเดอร์ย่อย) และ "!" ขัดแย้งกับ regex


คล้ายกัน แต่เฉพาะโฟลเดอร์ปัจจุบัน:find . \( ! -regex './\..*' \) -type f -maxdepth 1 -print
phyatt

2

คุณไม่ต้องใช้findสิ่งนั้น เพียงใช้ globstar ในตัวมันเองเช่น:

echo **/*foo*

หรือ:

ls **/*foo*

โดยที่**/แสดงถึงโฟลเดอร์ใด ๆ ที่เกิดซ้ำและ*foo*ไฟล์ใด ๆ ที่มีfooชื่ออยู่ในนั้น

โดยค่าเริ่มต้นการใช้lsจะพิมพ์ชื่อไฟล์ยกเว้นไฟล์และไดเรกทอรีที่ซ่อนอยู่

หากคุณไม่ได้มี globbing shopt -s globstarเปิดใช้งานทำมันด้วย

หมายเหตุ: ตัวเลือก globbing ใหม่ทำงานใน Bash 4, zsh และเชลล์ที่คล้ายกัน


ตัวอย่าง:

$ mkdir -vp a/b/c/d
mkdir: created directory 'a'
mkdir: created directory 'a/b'
mkdir: created directory 'a/b/c'
mkdir: created directory 'a/b/c/d'
$ touch a/b/c/d/foo a/b/c/d/bar  a/b/c/d/.foo_hidden a/b/c/d/foo_not_hidden
$ echo **/*foo*
a/b/c/d/foo  a/b/c/d/foo_not_hidden

5
คุณไม่ต้องการlsสิ่งนั้น! echo **/*foo*
Kevin Cox

@kenorb (และ @ kevin-cox) คุณจะพูดได้มากกว่านี้อีกไหม? ทำไม globstar (= *) ถึงทำงานที่นี่และอย่างไร เครื่องหมายทับ / ทำอะไร
บ๊องเกี่ยวกับ natty

@nuttyaboutnatty /หมายถึงโฟลเดอร์มันแยกไดเรกทอรีออกจากชื่อไฟล์ *โดยทั่วไปหมายถึงทุกอย่าง
kenorb

@kenorb ใช่ แต่: วิธีการหนึ่งซับช่วยด้วยคำถามเดิมได้อย่างไร
บ๊องเกี่ยวกับ natty

1
@nuttyaboutnatty ชี้แจงและเพิ่มตัวอย่างแล้ว ช่วยด้วยการค้นหาไฟล์โดยไม่สนใจไฟล์ที่ถูกซ่อน
kenorb

1

@ Flimm ของคำตอบที่เป็นสิ่งที่ดีอย่างยิ่งเพราะจะป้องกันไม่ให้พบจากมากไปหาน้อยลงในไดเรกทอรีที่ซ่อนอยู่ ฉันชอบความเรียบง่ายนี้:

โดยทั่วไปแล้วเพื่อยกเว้นเส้นทางที่ซ่อนอยู่ทั้งหมด (ไฟล์ปกติไดเรกทอรี ฯลฯ ):

find <start-point> -path '*/.*' -prune -o <expression> -print

ตัวอย่างเช่นการใช้ไดเรกทอรีทำงานของคุณเป็นจุดเริ่มต้นและ-name '*some text*'เป็นนิพจน์:

find . -path '*/.*' -prune -o -name '*some text*' -print

ตรงกันข้ามกับสิ่งที่คำตอบของ @ Flimm แนะนำไม่มีไฟล์ที่ซ่อนอยู่หรือไดเรกทอรีที่ซ่อนอยู่เป็นกรณีที่ง่าย -path '*/.*'แสดงออกเป็นจริงสำหรับเส้นทางใด ๆ (ไฟล์ปกติไดเรกทอรี ฯลฯ ) ที่มีในทันทีหลังจากที่แยกไฟล์ของคุณ. /ดังนั้นบรรทัดนี้จะตัดทั้งไฟล์และไดเรกทอรีที่ซ่อนอยู่

การอนุญาตให้ไฟล์ที่ซ่อนอยู่ในขณะที่ไม่รวมไดเรกทอรีที่ซ่อนอยู่เป็นกรณีที่ต้องใช้ตัวกรองเพิ่มเติม นี่คือที่ที่คุณจะรวม-type dไว้ในนิพจน์ที่ถูกตัด

find <start-point> -type d -path '*/.*' -prune -o <expression> -print 

ตัวอย่างเช่น:

find . -type d -path '*/.*' -prune -o -name '*some text*' -print

ในกรณี-type d -path '*/.*'นี้trueใช้สำหรับไดเร็กทอรีเท่านั้นและดังนั้นจึงมีเพียงการตัดไดเร็กทอรีเท่านั้น


0

findมีสวิตช์ตรรกะที่เรียบร้อยเช่น-andและ-notคุณสามารถใช้เพื่อประโยชน์ของคุณเพื่อค้นหาไฟล์ที่ตรงกันด้วยสองกฎดังนี้:

$ touch non_hidden_file.txt .hidden_file.txt somethings/.another_hidden_file.txt                                                 

$ find . -type f -name '*hidden_file*' -and \( -not -name ".*" \)                            
./non_hidden_file.txt

อย่างที่คุณเห็นfindใช้กฎสองข้อ -name '*hidden_file*'และ-and \( -not -name ".*" \)ค้นหาชื่อไฟล์ที่ตรงกับเงื่อนไขทั้งสอง - ชื่อไฟล์ด้วยhidden_fileแต่ไม่มีจุดนำ หมายเหตุเครื่องหมายทับด้านหน้าวงเล็บ - ใช้เพื่อกำหนดวงเล็บเป็นfindอาร์กิวเมนต์แทนการกำหนด subshell (ซึ่งหมายถึงวงเล็บหมายถึงอย่างอื่นโดยไม่มีเครื่องหมายทับ)


0
$ pwd
/home/victoria

$ find $(pwd) -maxdepth 1 -type f -not -path '*/\.*' | sort
/home/victoria/new
/home/victoria/new1
/home/victoria/new2
/home/victoria/new3
/home/victoria/new3.md
/home/victoria/new.md
/home/victoria/package.json
/home/victoria/Untitled Document 1
/home/victoria/Untitled Document 2

$ find . -maxdepth 1 -type f -not -path '*/\.*' | sed 's/^\.\///g' | sort
new
new1
new2
new3
new3.md
new.md
package.json
Untitled Document 1
Untitled Document 2

หมายเหตุ:

  • . : โฟลเดอร์ปัจจุบัน
  • ลบ-maxdepth 1เพื่อค้นหาแบบเรียกซ้ำ
  • -type f: ค้นหาไฟล์ไม่ใช่ไดเรกทอรี ( d)
  • -not -path '*/\.*' : อย่าส่งคืน .hidden_files
  • sed 's/^\.\///g': ลบส่วนที่นำหน้า./ออกจากรายการผลลัพธ์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.