รับฟิลด์สุดท้ายโดยใช้ awk substr


109

ฉันพยายามใช้awkเพื่อรับชื่อไฟล์ที่กำหนดเส้นทางที่แน่นอนไปยังไฟล์
ตัวอย่างเช่นเมื่อกำหนดเส้นทางการป้อนข้อมูล/home/parent/child/filenameฉันต้องการให้filename ฉันได้ลอง:

awk -F "/" '{print $5}' input

ซึ่งทำงานได้อย่างสมบูรณ์แบบ
อย่างไรก็ตามฉันเข้ารหัสยาก$5ซึ่งอาจไม่ถูกต้องหากข้อมูลของฉันมีโครงสร้างดังต่อไปนี้:

/home/parent/child1/child2/filename

ดังนั้นโซลูชันทั่วไปจึงต้องใช้ฟิลด์สุดท้ายเสมอ(ซึ่งจะเป็นชื่อไฟล์)

มีวิธีง่ายๆในการทำสิ่งนี้กับฟังก์ชัน awk substr หรือไม่?


2
เนื่องจากมีคนชี้ให้เห็นว่าการใช้basenameเป็นวิธีที่เป็นทางการในการทำเช่นนี้การใช้วิธีawkนี้ไม่ดีที่จะพูดเบา : D
Kashyap

คำตอบ:


222

ใช้ข้อเท็จจริงที่awkแยกเส้นในเขตข้อมูลตามตัวคั่นเขตข้อมูลที่คุณสามารถกำหนดได้ ดังนั้นการกำหนดตัวคั่นฟิลด์ให้/คุณสามารถพูดได้ว่า:

awk -F "/" '{print $NF}' input

ตามที่NFอ้างถึงจำนวนฟิลด์ของระเบียนปัจจุบันการพิมพ์$NFหมายถึงการพิมพ์รายการสุดท้าย

ได้รับไฟล์เช่นนี้:

/home/parent/child1/child2/child3/filename
/home/parent/child1/child2/filename
/home/parent/child1/filename

นี่จะเป็นผลลัพธ์:

$ awk -F"/" '{print $NF}' file
filename
filename
filename

3
มันทำงานได้อย่างสมบูรณ์ ฉันไม่ได้คิดถึงตัวแปร $ NF ขอบคุณสำหรับคำตอบที่ง่ายและมีประสิทธิภาพในทันที
มาริ

6
สำหรับหนึ่ง penult $(NF-1)ใช้
Itachi

1
กำลังเขียนสคริปต์เพื่อทำงานกับคำสั่งนักเทียบท่าและนี่ก็เป็นเคล็ดลับ ขอบคุณ!
Harlin

32

ในกรณีนี้ควรใช้basenameแทนawk:

 $ basename /home/parent/child1/child2/filename
 filename

5
@Mari FYI dirnameทำตรงกันข้ามและตัดไฟล์ไม่ใช่เส้นทาง
Chris Seymour

5

อีกตัวเลือกหนึ่งคือการใช้ทดแทนพารามิเตอร์bash

$ foo="/home/parent/child/filename"
$ echo ${foo##*/}
filename
$ foo="/home/parent/child/child2/filename"
$ echo ${foo##*/}
filename

5

หากคุณเปิดรับโซลูชัน Perl สิ่งที่คล้ายกับโซลูชัน awk ของ fedorqui:

perl -F/ -lane 'print $F[-1]' input

-F/ระบุ/ว่าตัวคั่นฟิลด์
$F[-1]เป็นองค์ประกอบสุดท้ายใน@Fอาร์เรย์ autosplit


1
ขอบคุณ. สิ่งนี้ช่วยให้ฉันได้รับฟิลด์สุดท้าย แต่เป็นหนึ่งฟิลด์ perl -F "/" -lane 'print $ F [-2]' input
riderchap

สิ่งนี้ใช้ได้ผลสำหรับฉันเมื่อได้รับจากอินพุตแบบ piped ลืมเรื่อง perl ไปโดยสิ้นเชิง
คริส

3

มันควรจะเป็นความคิดเห็นสำหรับคำตอบพื้นฐาน แต่ฉันยังไม่มีประเด็นเพียงพอ

หากคุณไม่ใช้เครื่องหมายคำพูดคู่basenameจะไม่ทำงานกับเส้นทางที่มีอักขระเว้นวรรค:

$ basename /home/foo/bar foo/bar.png
bar

ตกลงกับคำพูด ""

$ basename "/home/foo/bar foo/bar.png"
bar.png

ตัวอย่างไฟล์

$ cat a
/home/parent/child 1/child 2/child 3/filename1
/home/parent/child 1/child2/filename2
/home/parent/child1/filename3

$ while read b ; do basename "$b" ; done < a
filename1
filename2
filename3

3

ฉันรู้ว่าฉันชอบสิ่งนี้มา 3 ปีแล้ว แต่ .... คุณควรพิจารณาการขยายพารามิเตอร์ในตัวและเร็วกว่า

ถ้าใส่ของคุณอยู่ใน var ที่สมมติว่า $ var1 ${var1##*/}เพียงแค่ทำ ดูด้านล่าง

$ var1='/home/parent/child1/filename'
$ echo ${var1##*/}
filename
$ var1='/home/parent/child1/child2/filename'
$ echo ${var1##*/}
filename
$ var1='/home/parent/child1/child2/child3/filename'
$ echo ${var1##*/}
filename

2

เช่น 5 ปีที่ผ่านมาฉันรู้ขอบคุณสำหรับข้อเสนอทั้งหมดฉันเคยทำสิ่งนี้ด้วยวิธีต่อไปนี้:

$ echo /home/parent/child1/child2/filename | rev | cut -d '/' -f1 | rev
filename

ดีใจที่สังเกตเห็นว่ามีมารยาทที่ดีขึ้น


-1

คุณยังสามารถใช้:

    sed -n 's/.*\/\([^\/]\{1,\}\)$/\1/p'

หรือ

    sed -n 's/.*\/\([^\/]*\)$/\1/p'

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