วิธีใช้คำสั่ง find เพื่อแสดงชื่อไฟล์ แต่ไม่ใช่พา ธ ?

Jan 06 2021

ฉันได้ตรวจสอบคำตอบทางออนไลน์แล้ว แต่ไม่ได้ผลเมื่อมี-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нιηเตือนไว้

คำตอบ

3 αғsнιη Jan 06 2021 at 21:02

เมื่อใช้หลายนิพจน์ในโหมดตรรกะ OR โดย-oคุณต้องใส่ไว้ในนั้นทั้งหมด\( ... \)มิฉะนั้นผลลัพธ์ของนิพจน์สุดท้ายจะได้รับการยอมรับ และ-printf '%f\n'ใช้เพื่อพิมพ์ชื่อไฟล์เฉพาะกับไดเร็กทอรีชั้นนำใด ๆ ที่ถูกลบออก

find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'

ดูman findภายใต้ผู้ประกอบการส่วนที่เกี่ยวกับ( expr ):

ผู้ปฏิบัติงาน
...

(expr)
บังคับลำดับความสำคัญ เนื่องจากวงเล็บเป็นสิ่งพิเศษสำหรับเชลล์โดยปกติคุณจะต้องพูดถึงมัน

ดังนั้นคุณสามารถใช้\( ... \)หรือ'(' ... ')'(ช่องว่างหลังและก่อนวงเล็บมีความสำคัญ) เพื่อหลีกเลี่ยง

1 Kusalananda Jan 06 2021 at 22:58

ดังที่ได้กล่าวไปแล้วคุณต้องจัดกลุ่ม-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'ทำสิ่งเดียวกันได้