เราสามารถพิมพ์คำสุดท้ายของแต่ละบรรทัดใน linux โดยใช้คำสั่ง sed ได้หรือไม่?


9

สมมติว่าหากมีไฟล์ประกอบด้วยบรรทัดต่อไปนี้ถ้าเป็น

12345 567 7878 66

   er3 t45t y6y46y 


 4y6 y656y y5y

   46y6 65 ปี 7 y66uyuy

 yy46y6y

ผลลัพธ์ต้องมีลักษณะดังนี้:

66

y6y46y

y5y

y66uyuyy

y46y6y

ฉันได้ลองใช้sed 's/.* //g'ชื่อไฟล์คำสั่งและsedคำสั่งอื่น ๆแล้ว แต่มันไม่ทำงาน

ฉันจะรู้ได้อย่างไรว่าsedคำสั่งที่แน่นอนคืออะไร?


จำเป็นต้องใช้sedหรือไม่
coffeMug

คำตอบ:


8
awk '{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//'

นั่นยังคงพิมพ์บรรทัดว่างสำหรับทุกบรรทัดว่าง เพื่อหลีกเลี่ยงมัน:

awk 'NF{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//;/./!d'

ทางเลือกการแสดงออกเดียว: sed -n 's/.*[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]]*$/\1/p'.
jimmij

@jimmij - อันนั้นไม่ทำงานถ้าลำดับสุดท้ายที่ไม่ว่างเป็นลำดับแรกและไม่มีช่องว่างก่อนหน้า นอกจากนี้คุณอาจได้เป็นอย่างดีเพียงแค่ทำ.*ที่หางอาจ - คุณออกกฎอะไร แต่ท้ายช่องว่างอยู่แล้ว w .*[^[:blank:]]/
mikeserv



4

คุณเกือบจะแล้ว เพียงระบุคำสุดท้าย:

sed 's/^.* \([^ ][^ ]*\)/\1/g'

มันทำอะไร:

  1. '^. *' จะลบทุกอย่างภายในจุดเริ่มต้นของบรรทัดและช่องว่างใด ๆ
  2. '\ (... ) \' จับคู่รูปแบบและส่งคืนเป็น \ 1
  3. '[^]' จับคู่ทุกอย่างโดยไม่มีช่องว่าง

(แก้ไขเพื่อเพิ่มโซลูชันที่ดีขึ้นขอบคุณ Hildred!)


1
นี่คือนิพจน์ที่สั้นกว่า: sed -r 's/.* ([^ ]+)/\1/g'หากอนุญาตให้ใช้นิพจน์ทั่วไปเพิ่มเติมซึ่งโดยปกติจะเป็นกรณี
mkalkov

รุ่นที่สั้นกว่าโดยใช้สิ่งที่คุณไม่ต้องการเก็บไว้แทนที่จะเป็นสิ่งที่คุณต้องการเก็บไว้:sed 's/.* //'
Uriel

2

ตัวอย่างเช่นคุณสามารถใช้รูปแบบที่เพียงพอgrepแทนsed:

grep -o "[a-Z0-9]*$"

ในตัวอย่าง[...]นี้ช่วงประกอบด้วยอักขระที่เหมาะสมสำหรับ "คำว่า" (ตัวอักษรและตัวเลขในกรณีนี้สามารถเพิ่มสัญลักษณ์อื่นได้ซึ่งบางอันต้องมีการหลบหนี)


3
สมมติว่าไม่มีที่ว่างที่ท้ายบรรทัด a-Zเป็นช่วงที่ไม่เข้าท่าแม้แต่ในสถานที่ที่ใช้ ASCII โปรดทราบว่า-oเป็นส่วนขยายของ GNU
Stéphane Chazelas

0

หากคุณมีคุณสมบัติคำว่าหมายถึงลำดับของอักขระที่ไม่ว่าง 1 ตัวหรือมากกว่านั้นคำตอบคือใช่แน่นอนและมันก็ทำได้ง่ายเช่นกัน นี่เป็นเพราะ[[:blank:]]*และ[^[:blank:]]*เป็นบูลีนที่เติมเต็มและ - ให้อักขระทั้งหมดในสตริงสมบูรณ์ - [[:blank:]]*U [^[:blank:]]*สามารถอธิบายสตริงที่เป็นไปได้ในลักษณะเดียวกับที่.*ทำ

หากมีอักขระที่ไม่สมบูรณ์หรือลำดับไบต์ที่ไม่ถูกต้องมีอยู่ในสตริงจะไม่สามารถอธิบายได้ตั้งแต่ต้นจนจบ - ซึ่งบางครั้งอาจเกิดขึ้นเมื่อตีความสตริงในการเข้ารหัสผิด เพื่อให้มั่นใจว่าอักขระสมบูรณ์ต่อไบต์ในสตริงใด ๆ โลแคล C สามารถบังคับดังนี้:

LC_ALL=C sed ...

... ซึ่งจะหลีกเลี่ยงปัญหาใด ๆ ที่อธิบายถึงสตริงจากหัวถึงท้ายด้วยรูปแบบรวมทุกอย่างเช่น.*หรือ([ ]*[^ ]*)*

รูปแบบที่สมบูรณ์สามารถทำซ้ำได้บ่อยครั้งเท่าที่จำเป็นจากซ้ายไปขวาความยาวของสตริงใด ๆ ไปยังดินแดนที่เกิดขึ้นครั้งสุดท้ายที่เป็นไปได้โดยไม่ต้องหยุดพักในรูปแบบใด ๆ นี่คือภาษาปกติอย่างชัดเจน

BRE:

sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'

ERE:

sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'

ทั้งสองเวอร์ชันจะยังคงพิมพ์บรรทัดว่างและนี่เป็นเพราะ*ดาวKleene ตรงกับรูปแบบที่เกิดขึ้นเป็นศูนย์หรือมากกว่า มันตรงกับตัวอักษรที่เป็นศูนย์หรือมากกว่าไม่ว่างเปล่าแล้วตัวอักษรที่ว่างเปล่าเป็นศูนย์หรือมากกว่านั้นแล้วเกิดขึ้นเป็นศูนย์หรือมากกว่าของการแข่งขันที่จัดกลุ่มจนกว่าจะได้ตรงกับสตริงในสิ่งทั้งปวง

เมื่อจับคู่ทั้งหมดนี้เวทมนตร์จะเกิดขึ้นในการแทนที่ - การอ้างอิงที่ส่งคืนโดยกลุ่ม\1และ\2เป็นเหตุการณ์ล่าสุดของแต่ละรายการ ดังนั้นเมื่อเปลี่ยนเป็นทำทั้งหมดของสตริงจะถูกแทนที่ด้วยเพียงเกิดขึ้นครั้งล่าสุดในสายของศูนย์หรือมากกว่าไม่ได้ตัวละครที่ว่างเปล่า - \2หรือกลุ่มย่อย

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

b='[:blank:]'

ตอนนี้หากต้องการพิมพ์หากบรรทัดมีอักขระหนึ่งตัวหรือมากกว่าที่ไม่ใช่ว่างคุณสามารถทำได้:

BRE:

sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"

ERE:

sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
  1. กรณี BRE - การทดแทนจะดำเนินการเสมอและเว้นวรรครูปแบบที่มีอักขระที่เหลืออย่างน้อยหนึ่งตัวเท่านั้นที่จะถูกพิมพ์
  2. กรณี ERE - การแทนที่ถูกพยายามบนพื้นที่รูปแบบที่มีอักขระถ่านอย่างน้อยหนึ่งตัวเท่านั้น

ทั้งสองแบบจะทำงานกับวิธีใดวิธีหนึ่ง - ตราบใดที่ไวยากรณ์ถูกต้อง

-nสวิทช์ปิดการใช้งานอัตโนมัติการพิมพ์ของพื้นที่รูปแบบและpธงไปs///ubstitution หรือ/อยู่/คำสั่งพิมพ์ผลของมันเท่านั้นหากประสบความสำเร็จ

ตรรกะเดียวกันนี้สามารถนำไปใช้เพื่อให้{num}เกิดเหตุการณ์ใด ๆเช่นกันเช่น:

BRE:

sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"

ERE:

sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"

... โดยที่numทั้ง regexps สามารถถูกแทนที่ด้วยตัวเลขเพื่อพิมพ์เฉพาะ{num}เหตุการณ์ที่ระบุของลำดับของอักขระที่ไม่ว่างเปล่า รูปแบบที่แตกต่างกันเล็กน้อยถูกนำมาใช้ที่นี่เพื่อให้แน่ใจว่าการนับจะไม่เบ้สำหรับพื้นที่ชั้นนำในสตริง

โปรดทราบว่า-Eสวิตช์ ERE sedได้รับการสนับสนุนทั้งในรุ่น BSD และ GNU แม้ว่าจะยังไม่มีไวยากรณ์มาตรฐาน POSIX


คำอธิบายที่ดีแฮ็คที่ดี แต่โปรดทราบว่าจะไม่ทำงานกับการใช้งานแบบดั้งเดิม sed (เช่น Solaris / usr / bin / sed) และจะมีราคาแพงกว่าวิธีการที่ตรงไปตรงมามากขึ้น (หมดความทรงจำกับบรรทัดอินพุตมากกว่า 25 อักขระsed_su3จาก toolchest Heirloom เป็นต้น) ดังนั้นแม้ว่าฉันจะชอบคำตอบ แต่ฉันก็ไม่แนะนำวิธีการนั้น
Stéphane Chazelas

ดูเหมือนจะไม่ทำงานใน FreeBSD เช่นกัน
Stéphane Chazelas

@ StéphaneChazelas - ใช่การแสดงน่ากลัวจริง ๆ สำหรับสิ่งนี้ แต่สามารถมีประสิทธิภาพมากสำหรับการเลือกหมายเลขที่ปรากฏ และสำหรับจุดจบของเส้นกรณีs/.* \([^[:blank:]]\{1,\}\).*/\1/นั้นดีกว่ามาก แต่มันก็ยากกว่าเมื่อมีหลายสายเข้ามาเกี่ยวข้อง แต่เมื่อวันก่อนฉันค้นพบว่า's/\(\n\)*/\1/g;s/\n\(\n.*\)*/&&/[num];s///[samenum]สามารถช่วยได้อย่างมีประสิทธิภาพ อย่างไรก็ตามตราบใดที่ไม่มีข้อผิดพลาดที่จ้องมองในตรรกะแล้วฉันมีความสุข - ฉันแค่คิดว่าฉันต้องพลาดบางสิ่งบางอย่าง
mikeserv

@ StéphaneChazelas - โอ้และเกี่ยวกับผู้สูงอายุsed- มันแปลกเล็กน้อย - มันควรจะเป็นเสียงตามมาตรฐาน xrat บอกว่า ... นักพัฒนามาตรฐานถือว่าพฤติกรรมทางประวัติศาสตร์ทั่วไปซึ่งสนับสนุน"\n*"แต่ไม่ใช่"\n\{min,max\}", "\(...\)*"หรือ"\(...\)\{min,max\}"เป็นผลลัพธ์ที่ไม่ได้ตั้งใจของการใช้งานที่เฉพาะเจาะจงและพวกเขาสนับสนุนทั้งการทำซ้ำและนิพจน์ช่วงเวลาตามนิพจน์ย่อยและการอ้างอิงกลับ
mikeserv

@ StéphaneChazelas - และมาตรฐานบอกว่า ... หากนิพจน์ย่อยอ้างอิงโดยการอ้างอิงกลับจับคู่มากกว่าหนึ่งสตริงเนื่องจากเครื่องหมายดอกจัน( '*' )หรือนิพจน์ช่วงเวลา (ดูรายการ (5)) การอ้างอิงกลับจะต้องตรงกับครั้งสุดท้าย (ขวาสุด) ) ของสตริงเหล่านี้ ฉันค่อนข้างแน่ใจว่าฉันทดสอบสิ่งนี้ด้วยminised- แน่นอนว่าฉันกำลังทดสอบบางสิ่งแปลก ๆminisedกับวันอื่น ๆ อยู่ดี
mikeserv

0
sed 's/^ star.star //'  filename  or sed 's/^[[:blank:]]star.star[[:blank:]]//' filename

วิเคราะห์:

  • s - ทดแทน

  • / - เริ่มต้นของการแสดงออกที่จะมองหา

  • ^ - จากจุดเริ่มต้นของบรรทัด

  • [[:blank:]]* - หากมีช่องว่างที่จุดเริ่มต้นของบรรทัดในกรณี

  • .* - ตัวละครใด ๆ

  • [[:blank:]] - และอักขระว่าง

  • / - จุดเริ่มต้นของการแสดงออกเพื่อทดแทน

  • / - สิ้นสุดไวยากรณ์คำสั่ง

PS: ฉันได้เขียนดาวไว้ในคอมมอนด์


สิ่งนี้จะนำไปใช้กับข้อมูลที่ให้ไว้ในคำถามได้อย่างไร
Kusalananda

@Scott s/.*[[:blank:]]//จะทำงานได้หากไม่มีช่องว่างที่ท้ายบรรทัด
Kusalananda

-1

ใช่. คำสั่ง sed ต่อไปนี้ก่อนจะลบ whitespaces ต่อท้ายทั้งหมด ( s/ *$//) และจากนั้นทุกอย่างจนถึงและรวมถึง whitespace ล่าสุด ( s/.* //) มันอาจจะคุ้มค่าที่จะแทนที่ช่องว่างที่แท้จริง[[:blank:]]เพื่อจับแท็บและอักขระที่มีลักษณะคล้ายช่องว่างอื่น ๆ

$ echo "  aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  cc  " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "cc" | sed -e 's/ *$//' -e 's/.* //'
cc

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