วิธีรับชื่อไฟล์โดยใช้ sed เท่านั้น


17

ฉันจะได้รับชื่อไฟล์โดยใช้ sed เท่านั้นได้อย่างไร ฉันนี้

out_file=$(echo $in_file|sed "s/\(.*\.\).*/\1mp4/g")

แต่ฉันได้รับเส้นทางเกินไปและฉันต้องการเพียง/root/video.mp4video.mp4

คำตอบ:


26

basenameจากcoreutils ของ GNU สามารถช่วยคุณทำงานนี้ได้:

$ basename /root/video.mp4
video.mp4

หากคุณรู้จักส่วนขยายของไฟล์อยู่แล้วคุณสามารถเรียกbasenameใช้โดยใช้ไวยากรณ์basename NAME [SUFFIX]เพื่อที่จะลบมัน:

$ basename /root/video.mp4 .mp4
video

หรือตัวเลือกอื่นจะตัดทุกอย่างหลังจากจุดสุดท้ายโดยใช้sed:

$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old

3
การใช้sed 's/\.[^.]*$//'ที่คุณมีจะล้มเหลว (ซ่อนไว้) .filenameและ.และ..ไดเรกทอรี
Peter.O

9

ทางออกที่ง่ายที่สุดคือการลบทุกอย่างจนกระทั่งการปรากฏตัวครั้งสุดท้ายของ/:

echo /root/video.mp4 | sed 's/.*\///'


5

ใช้วิธีต่อไปนี้:

out_file="${in_file##*/}"

out_file="$(basename $in_file)"

out_file="$(echo $in_file | sed 's=.*/==')"

out_file="$(echo $in_file | awk -F"/" '{ print $NF }')"

PS คุณได้รับสายอักขระเดียวกันเนื่องจากในคำสั่งของคุณ\(.*\.\)ตรงกับสายอักขระจากจุดเริ่มต้นจนถึงจุด ( /root/video.) และจากนั้นคุณเพิ่มด้วยตนเอง.mp4ซึ่งเป็นเหมือนในสายอักขระเดิมของคุณ คุณควรใช้s=.*\([^/]*\)=\1=แทน

อัปเดต: (อันแรกได้รับการแก้ไขแล้ว)

ในการรับชื่อไฟล์ที่ไม่มีนามสกุลคุณสามารถ:

out_file="$(echo $in_file | sed 's=.*/==;s/\.[^.]*$/.new_ext/')"

out_file="$(echo $in_file | sed 's=\([^/]*\)\.[^./]*$=\1.new_ext=')"

out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'

แต่ด้วยวิธีการเหล่านี้ฉันได้รับชื่อไฟล์ด้วยรูปแบบและฉันต้องได้รับชื่อไฟล์เท่านั้นและใส่รูปแบบใหม่ด้วยตนเอง
Shixons

อ่านั่นสมเหตุสมผลแล้ว ฉันอัพเดตคำตอบแล้ว
เร่ง

@rush: my.file.tar.gzจะมีกรณีขอบเช่นสำหรับไฟล์ชื่อ
donothingsuccessfully

@donothingsuccessfully มีการขาดหายไปสัญลักษณ์จุดในช่วงและsed awkแก้ไขแล้ว. ขอขอบคุณ.
เร่ง

4

หนึ่งในปัจจัยพื้นฐานของการใช้ regex คือรูปแบบนั้นโลภโดยธรรมชาติเมื่อระบุ wild card ในขณะที่คำตอบที่เสนอโดย @uloBasEI เป็นคำตอบที่ใช้งานได้จริง แต่ก็ต้องใช้คำสั่ง basename ด้วย คำถามดั้งเดิมจาก @Shixons ร้องขอวิธีการแก้ปัญหาโดยใช้ sed เท่านั้น

ก่อนดำเนินการต่อจะเป็นประโยชน์เสมอที่จะทราบว่ารุ่นของ sed ใดที่เป็นเป้าหมาย ฉันสมมติว่า BSD (จัดส่งมาพร้อมกับ OSX)

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

ขั้นตอนแรกคือการสร้างกลยุทธ์สำหรับการระบุรูปแบบ ที่นี่คุณต้องการกำจัดทุกอย่างทางด้านซ้ายของชื่อไฟล์ (เราจะจัดการกับส่วนขยายในภายหลัง):

out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"

การค้นหาตรงกันจากจุดเริ่มต้นของสตริง มันตรงกับรูปแบบของ "/.*" ศูนย์หรือมากกว่านั้นและลบทุกอย่างในภายหลัง เราพิมพ์รูปแบบที่ตรงกันด้วย "\ 1" เราไม่ได้ค้นหาทั่วโลก เรากำลังค้นหาตั้งแต่เริ่มต้นของสตริงโดยการระบุ ^ anchor

เราได้ความชัดเจนที่ดีขึ้นโดยการเปิดใช้งานตัวเลือก "-E" ดังนั้นเราจึงไม่ต้องหลบเลี่ยงวงเล็บ:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"

ดังนั้นตอนนี้เรามีส่วนทางด้านซ้าย ลองเพิ่มส่วนทางด้านขวา โปรดทราบว่าเราต้องเก็บส่วนซ้ายไว้เป็นรูปแบบเนื่องจากเป็นวิธีที่เราสามารถระบุได้ว่าจะปรากฏเป็นศูนย์หรือมากกว่านั้น สิ่งที่เราทำตอนนี้คือการเพิ่มรูปแบบสำหรับส่วนทางด้านขวา:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"

เราพิมพ์คู่ที่สองเท่านั้นดังนั้นจึงละทิ้งทุกอย่างยกเว้นชื่อไฟล์ แต่เรายังต้องลบส่วนขยายชื่อไฟล์

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"

"$" ในตอนท้ายเป็นตัวเลือก

ในที่สุดหากต้องการเพิ่มส่วนขยายใหม่คุณเพียงแก้ไขดังนี้

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"

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

out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"

ฉันมาข้ามคำถามนี้โดยเป็นขี้เกียจในขณะที่มองหารูปแบบ sed เพื่อแทนที่basename ฉันกำลังทำงานกับระบบที่ปล้นซึ่งไม่มีคำสั่งนั้นติดตั้งอยู่

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