วิธีใช้คำสั่ง find เพื่อแสดงชื่อไฟล์ แต่ไม่ใช่พา ธ ?
ฉันได้ตรวจสอบคำตอบทางออนไลน์แล้ว แต่ไม่ได้ผลเมื่อมี-name
พารามิเตอร์ในคำสั่ง (บางทีฉันอาจทำอะไรผิดพลาดไม่แน่ใจ) สิ่งที่ฉันต้องการทำคือแสดงเฉพาะชื่อไฟล์ (ไม่ใช่ไดเรกทอรี / เส้นทาง) และเพื่อให้ซับซ้อนยิ่งขึ้นฉันมีชื่อไฟล์เดียวกันที่มีนามสกุลต่างกันดังนั้นฉันต้องกรองผลลัพธ์โดยใช้-name
และ-o
ปัญหาคือคำแนะนำที่ฉัน ใช้เลื่อยอย่างใดอย่างหนึ่ง-printf
หรือและผู้ที่ไม่ได้ทำงานได้ดีเมื่อมีbasename
-name *.txt -o name *.pdf
มีวิธีอื่นในการแก้ปัญหานี้หรือไม่?
ตัวอย่างไฟล์ของฉัน:
/dir1/dir2/dir3/dir4/
/file1.txt
/file1.pdf
/file1.ods ...etc.
ฉันสนใจที่จะแสดงรายการไฟล์อย่างน้อยหนึ่งประเภทต่อรายการเท่านั้น (โดยใช้-name
เพื่อกรองผลลัพธ์ของฉัน
เป็นไปได้ไหมที่จะทำมันให้สำเร็จโดยใช้เพียง 1 find
คำสั่งหรือฉันต้องทำใน 2 ขั้นตอน (บันทึกผลลัพธ์ในไฟล์ชั่วคราวจากนั้นกรอง / ตัดไดเร็กทอรีออกจากไฟล์ temp) ผลลัพธ์ที่ฉันพยายามทำให้สำเร็จคือไฟล์ข้อความที่มีชื่อไฟล์ต่อบรรทัด:
file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.
คำสั่งที่ฉันใช้คือ
find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"
ฉันใช้ GNU find
อัปเดต
ปรากฎว่าฉันต้องใส่\(...\)
ตามที่αғsнιηเตือนไว้
คำตอบ
เมื่อใช้หลายนิพจน์ในโหมดตรรกะ OR โดย-o
คุณต้องใส่ไว้ในนั้นทั้งหมด\( ... \)
มิฉะนั้นผลลัพธ์ของนิพจน์สุดท้ายจะได้รับการยอมรับ และ-printf '%f\n'
ใช้เพื่อพิมพ์ชื่อไฟล์เฉพาะกับไดเร็กทอรีชั้นนำใด ๆ ที่ถูกลบออก
find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'
ดูman findภายใต้ผู้ประกอบการส่วนที่เกี่ยวกับ( expr )
:
ผู้ปฏิบัติงาน
...(expr)
บังคับลำดับความสำคัญ เนื่องจากวงเล็บเป็นสิ่งพิเศษสำหรับเชลล์โดยปกติคุณจะต้องพูดถึงมัน
ดังนั้นคุณสามารถใช้\( ... \)
หรือ'(' ... ')'
(ช่องว่างหลังและก่อนวงเล็บมีความสำคัญ) เพื่อหลีกเลี่ยง
ดังที่ได้กล่าวไปแล้วคุณต้องจัดกลุ่ม-name
การทดสอบของคุณในวงเล็บ วงเล็บเหล่านี้จำเป็นต้องหลีกเลี่ยงเป็น\( ... \)
หรือยกมาเป็นเช่น'(' ... ')'
เพื่อป้องกันพวกมันจากเชลล์ (โดยที่พวกเขาจะกำหนดให้เป็นเชลล์ย่อย)
ใช้มาตรฐานfind
และทำให้การจัดการคำต่อท้ายชื่อไฟล์ง่ายขึ้นเล็กน้อย:
set -- txt pdf ods
for suffix do
set -- "$@" -o -name "*.$suffix"
shift
done
shift
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;
ขั้นแรกตั้งค่าพารามิเตอร์ตำแหน่งเป็นรายการคำต่อท้ายชื่อไฟล์ที่เราต้องการดู (สามารถนำมาจากบรรทัดคำสั่งหากนี่เป็นสคริปต์) และสร้างรายการหรือรายการ-name
การทดสอบ จากนั้นจะใช้ในfind
บรรทัดคำสั่ง
จากนั้นfind
คำสั่งจะเรียกbasename
ยูทิลิตี้สำหรับแต่ละชื่อที่พบ
อีกทางเลือกหนึ่งเราสามารถใช้การแทนที่พารามิเตอร์เพื่อลบส่วนประกอบทั้งหมดยกเว้นชื่อไฟล์ของแต่ละชื่อพา ธ แต่ในการทำเช่นนั้นเราต้องส่งชื่อพา ธ ไปยังsh -c
สคริปต์อินไลน์:
# [...] as before [...]
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
for pathname do
printf "%s\n" "${pathname##*/}"
done' sh {} +
ฉันคาดหวังว่าสิ่งนี้จะทำงานได้เร็วกว่ารูปแบบที่ใช้basename
อย่างน้อยถ้ามีชื่อไฟล์จำนวนมากให้จัดการแม้ว่าจะใช้ GNU basename
จาก coreutils คุณสามารถใช้-a
หรือ--multiple
ชอบได้:
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +
สิ่งนี้จะโทรbasename
น้อยครั้งที่สุด แต่อีกครั้งถ้าคุณติดตั้ง coreutils คุณอาจมี findutils ด้วยเช่นกันกับ GNU find
และสามารถใช้-printf '%f\n'
ทำสิ่งเดียวกันได้