ฉันจะใช้ `find 'เพื่อไปยังไดเรกทอรีของไฟล์นั้นได้อย่างไร


11

ฉันต้องการค้นหาไฟล์จากนั้นป้อนไดเรกทอรีที่มีไฟล์ ฉันพยายามfind /media/storage -name "Fedora" | xargs cdแต่แน่นอนฉันis not a directoryผิดพลาด

ฉันจะป้อนไดเรกทอรีหลักด้วยคำสั่งหนึ่งบรรทัดได้อย่างไร


1
และถ้าเกิดมีไฟล์หลายไฟล์จากหลาย ๆ ที่?
Sergiy Kolodyazhnyy

@Serg ฉันกำลังค้นหาไฟล์ Fedora * .iso และฉันรู้ว่ามีเพียงไฟล์เดียว หากมีมากกว่าหนึ่งมันจะเข้าสู่ direcotry แรกฉันเดา
Hrvoje T

ในการทุบตีด้วยshopt -s globstarคุณทำได้cd /media/storage/**/Fedoraแต่นั่นไม่ได้หยุดประเมิน glob ในนัดแรก (ดังนั้นจึงช้ากว่าโซลูชันของ steeldriver สำหรับการใช้งานแบบโต้ตอบสิ่งที่ฉันมักจะทำคือเข้าถึงเมาส์และคัดลอก / วางชื่อไดเรกทอรี (และ alt + backspace ตามต้องการเพื่อแยกองค์ประกอบของเส้นทางที่ฉันไม่ต้องการ) แต่ถ้าคุณทำสิ่งนี้มากฉันคิดว่าฟังก์ชั่นของเชลล์น่าจะคุ้มค่า
Peter Cordes

1
BTW xargs cdไม่สามารถทำงานได้ cdสามารถทำงานเป็นเชลล์บิวด์อินได้เท่านั้นเนื่องจากต้องแก้ไขบริบทของเชลล์เอง ไม่มีวิธีที่xargsกระบวนการลูกสามารถทำได้ IDK ถ้านั่นคือสิ่งที่คุณหมายถึงโดย "แน่นอน" หรือหากเส้นทางที่findพิมพ์มีช่องว่างซึ่งจะถูกแยกด้วย xargs เนื่องจากคุณไม่ได้ใช้-d \nหรืออะไรก็ตาม find -exec {} \;หรือ
Peter Cordes

หมายเหตุ: คุณไม่สามารถเรียกใช้cdเช่นนั้น cdเป็นทุบตีในตัวถ้าcdเป็นคำสั่งที่แยกต่างหากจากนั้นมันจะเปลี่ยน dir (ของมันเอง) แล้วออกจาก (กลับคุณไปที่เปลือกหอยที่อยู่ในสถานะเดียวกับก่อนไม่มีการเปลี่ยนแปลงของ dir)
ctrl-alt-delor

คำตอบ:


14

อย่างน้อยถ้าคุณมี GNU findคุณสามารถใช้-printf '%h'เพื่อรับไดเรกทอรี

       %h     Leading directories of file's name (all but the last ele‐
              ment).  If the file name contains no slashes (since it is
              in  the  current  directory)  the %h specifier expands to
              ".".

ดังนั้นคุณอาจจะทำ

cd "$(find /media/storage -name "Fedora" -printf '%h' -quit)"

-quitควรป้องกันไม่ให้เกิดข้อโต้แย้งหลายที่cdในกรณีที่มากกว่าหนึ่งแมตช์ไฟล์


1
-quitไม่รองรับเช่นกัน ใน NetBSD เรียกว่า-exitดูunix.stackexchange.com/a/62883/117599
phk

2
หากไม่มี printf คุณสามารถทำ -exec dirname แทนได้หรือไม่?
Guy

@ ซื้อความคิดที่ดีใช่ว่าดูเหมือนว่ามันควรจะทำงานด้วย
ช่างเหล็ก

6

คล้ายกับโซลูชันของ steeldriverแต่ใช้-execdir(หากคุณfindรองรับเช่น GNU หรือ FreeBSD find) ร่วมกับpwd:

cd "$(find /media/storage -name "Fedora" -execdir pwd \; -quit)"

-quitเป็นทางเลือกในกรณีที่มีเพียงผลลัพธ์เดียวเท่านั้นและการรวบรวมข้อมูลไดเรกทอรีทั้งหมดไม่มีปัญหา บน NetBSD มัน-exitและบน OpenBSD มันไม่มีอยู่จริง


และมี\;ไว้เพื่ออะไร?
Hrvoje T

1
@HrvojeT เช่นเดียวกับที่-execมันบอกfindเกี่ยวกับจุดสิ้นสุดของพารามิเตอร์สำหรับคำสั่งในการดำเนินการ แต่เนื่องจากเราต้องการโทรpwdโดยไม่มีพารามิเตอร์ที่นี่เราจึงใส่\;มันทันที
phk

มีfindการนำไปใช้งานที่รองรับ execdir -printf %hหรือไม่? ดูเหมือนไม่น่าสำหรับฉัน น่าเสียดายที่ POSIX ไม่ต้องการใคร: /
Peter Cordes

1
@PeterCordes ของ FreeBSD find: freebsd.org/cgi/man.cgi?find%281%29 (เพิ่งยืนยันในการติดตั้ง FreeBSD 11)
phk

@PeterCordes เดียวกันสำหรับ NetBSD ( netbsd.gw.com/cgi-bin/man-cgi?find++NetBSD-current ) และ OpenBSD ( man.openbsd.org/OpenBSD-current/man1/find.1 ) หลังไม่สนับสนุน-quit/ -exitเลย
phk

5

คุณสามารถทำการค้นหารันเชลล์ใหม่ในไดเร็กทอรีที่พบ

exec find /media/storage -name "Fedora" -execdir "$SHELL" \;

หลังจากนั้นไดเรกทอรีปัจจุบันจะเป็นไดเรกทอรีที่มีไฟล์ชื่อ Fedora อยู่ ;)

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


4

ด้วยzsh:

cd /media/storage/**/Fedora([1]:h)

ที่จะcdเข้ามาในครั้งแรก (เรียงตามลำดับตัวอักษร) Fedoraไดเรกทอรีที่มีไฟล์ที่เรียกว่า

  • **: ไดเรกทอรีระดับใด ๆ (dirs ที่ซ่อนอยู่จะถูกละเว้นโดยค่าเริ่มต้นใช้ตัวระบุแบบDกลมเพื่อรวมไว้)
  • [1]: เฉพาะคนแรก
  • :h: ตัวดัดแปลงส่วนหัว : จด dirname

ตรงกันข้ามกับcd "$(find ...)"มันยังใช้งานได้หากชื่อไดเรกทอรีลงท้ายด้วยอักขระขึ้นบรรทัดใหม่ ข้อดีอีกอย่างคือคุณจะได้รับข้อความแสดงข้อผิดพลาดที่ไม่ตรงกันเมื่อไม่มีไดเรกทอรีที่ตรงกัน (ในเชลล์ส่วนใหญ่cd ""จะไม่ทำสิ่งใดอย่างเงียบ ๆ )

ข้อเสียเปรียบคือมันจะรวบรวมข้อมูลทั้งหมด/media/storageก่อนกลับมา


ในทุบตีcdด้วย args หลาย ๆ ดูที่ arg แรกเท่านั้นดังนั้นcd $(dirname /media/storage/**/Fedora)จะทำงาน (ด้วยshopt -s globstar) หากไม่มีช่องว่างในเส้นทาง target=(/media/storage/**/Fedora); cd "${target%/*}"จะได้รับมันยกมาอย่างถูกต้องผมคิดว่าอาร์เรย์ทุบตีที่ง่ายที่สุดคือ: แต่ ณ จุดนี้มันจะเร็วกว่าที่จะใช้เมาส์เพื่อคัดลอก / วางค้นหาผลลัพธ์แทนที่จะมากับการโต้ตอบ
Peter Cordes

2
@PeterCordes dirnameการใช้งานหลายอย่างไม่ยอมรับอาร์กิวเมนต์มากกว่าหนึ่งรายการ โปรดทราบว่าไม่ใช่ช่องว่างปัจจุบันเป็นอักขระใด ๆ ใน$IFS(ช่องว่างแท็บและบรรทัดใหม่ตามค่าเริ่มต้น) และอักขระตัวแทน โปรดทราบว่าไม่ว่าจะเป็นbash's cdจะยอมรับมากกว่าหนึ่งข้อโต้แย้งขึ้นอยู่กับวิธีการที่จะได้รับการรวบรวม ( CD_COMPLAINSในconfig-top.h) ใคร ๆ ก็นึกได้ว่าในอนาคตเวอร์ชั่นของเวอร์ชั่นbashจะใช้ฟีเจอร์หาเรื่องทั้งสองอย่างเช่นใน zsh
Stéphane Chazelas

ขอบคุณ ฉันเพิ่งดู GNU coreutils manpage dirname เวอร์ชั่น dirname นั้นแย่มากอยู่ดี ฉันแค่พูดถึงมันเป็นสิ่งที่คุณอาจลองโต้ตอบในกรณีที่มันใช้งานได้ เวอร์ชันที่ใช้อาเรย์ของฉันไม่ได้ประสบปัญหาใด ๆ เนื่องจาก"${target%*/}"ขยายไปยังองค์ประกอบอาเรย์แรกเท่านั้น (ที่มีการ/Fedoraปล้น) ฉันคิดว่าเวอร์ชั่นนั้นแข็งแกร่งมากเมื่อเทียบกับตัวละครที่เป็นไปได้ในชื่อพา ธ
Peter Cordes
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.