awk sed ถ้ามีคำสั่ง


9

ฉันกำลังพยายามเพิ่ม 0 ถึงจุดเริ่มต้นหากมี "" ที่อักขระที่ 2 ของบรรทัดนั้น ฉันไม่สามารถรวมสองสิ่งนี้เข้าด้วยกันได้

awk '{ print substr( $0, 2, 1 ) }' file.txt 

แสดงตัวอักษรที่สอง

sed -ie "s/.\{0\}/0/" file.txt

เพิ่มศูนย์ถึงจุดเริ่มต้น

ควรมี "ถ้าอักขระตัวที่สองคือจุด"

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

1.02.2017 23:40:00
10.02.2017 23:40:00

สุดท้าย:

01.02.2017 23:40:00
10.02.2017 23:40:00

คำตอบ:


12

เราอาจใช้วิธีใดวิธีหนึ่งsedหรือawkเพื่อแก้ปัญหาอย่างสมบูรณ์


ด้วยsed:

$ sed 's/^.\./0&/' file.txt

เมื่อ&เกิดขึ้นในส่วนการแทนที่ของคำสั่งการแทนที่ ( s) มันจะถูกขยายไปยังส่วนของบรรทัดอินพุตที่ตรงกับส่วนรูปแบบของคำสั่ง

นิพจน์ทั่วไป^.\.หมายถึง " จับคู่ทุกบรรทัดที่ขึ้นต้นด้วย ( ^) อักขระใด ๆ ( .) ตามด้วยตัวอักษรจุด ( \.) "

หากบรรทัดอยู่1.02.2017 23:40:00รูปแบบจะจับคู่และ1.จะถูกแทนที่ด้วย01.ที่จุดเริ่มต้นของบรรทัด


ด้วยawk:

การสร้างawkรหัสบางส่วนในคำถาม ...

ตามที่ระบุไว้นี้พิมพ์อักขระตัวที่สองของแต่ละบรรทัดของอินพุต:

$ awk '{ print substr($0, 2, 1) }' file.txt

เราสามารถใช้ข้อเท็จจริงที่substr($0, 2, 1)ส่งคืนอักขระตัวที่สองและใช้เป็นเงื่อนไขได้:

$ awk 'substr($0, 2, 1) == "." { ... }' file.txt

สิ่งที่เข้าสู่{ ... }คือโค้ดที่ prepends $0ซึ่งเป็นเนื้อหาของบรรทัดปัจจุบันโดยมีศูนย์ถ้าเงื่อนไขก่อนหน้าเป็นจริง:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 }' file.txt

จากนั้นเราต้องตรวจสอบให้แน่ใจว่ามีการพิมพ์บรรทัดทั้งหมด:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 } { print }' file.txt

substr($0, 2, 1) == "."แน่นอนว่าเงื่อนไขอาจถูกเปลี่ยนเป็นนิพจน์ทั่วไปด้วย (เราใช้นิพจน์เดียวกับที่ใช้ในการsedแก้ปัญหา):

$ awk '/^.\./ { $0 = "0" $0 } { print }' file.txt

บางคนที่คิดว่า "สั้นกว่าดีกว่าเสมอ" จะเขียนว่าเป็น

$ awk '/^.\./ { $0 = "0" $0 } 1' file.txt

(และอาจลบการเว้นวรรคส่วนใหญ่ด้วยawk '/^.\./{$0="0"$0}1' file.txt)


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

ในความคิดของฉัน "ถูกต้อง" วิธีการ (ซึ่งไม่คุ้นเคยกับพื้นที่และมีน้ำหนักเบาอยู่แล้ว) sed 's/^.\./0&/' file.txtเป็นรุ่นสุดท้ายของคุณ ฉันคิดว่าคุณควรระบุไว้ในตอนต้นของคำตอบนี้ ถึงกระนั้น +1
Wildcard

1
@ Wildcard เรามุ่งมั่นที่จะโปรด
Kusalananda

5

ด้วย sed:

sed -e "/^.\./s/^/0/" file.txt 

รูปแบบ/^.\./จะค้นหาอักขระและจุดตัวอักษรที่จุดเริ่มต้นของบรรทัด^และหากตรงกับsรูปแบบนั้นจุดเริ่มต้นของบรรทัดที่มีศูนย์จะเพิ่มศูนย์ไปยังจุดเริ่มต้นอย่างมีประสิทธิภาพ

นิพจน์ sed ที่s/.\{0\}/0/ค่อนข้างแปลกมันจับคู่สำเนาของอะไรก็ได้ที่มีค่าเป็นศูนย์หรือมากกว่าและแทนที่ด้วยศูนย์ แน่นอนว่ารูปแบบจะจับคู่ในทุกตำแหน่งของสตริง แต่เนื่องจากs///แทนที่การจับคู่ครั้งแรกเท่านั้นจึงใช้งานได้ตามที่คุณต้องการ แต่วิธีที่แปลกตาที่จะทำมัน


หรือด้วย awk, regex ที่คล้ายกันจะทำงานเพื่อให้ตรงกับบรรทัด แต่เราสามารถใช้substr:

awk 'substr($0, 2, 1) == "." {$0 = "0" $0} 1' file.txt 

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


4

คุณพูดว่า awk และ sed แต่ดูเหมือนว่าคุณกำลังพยายามจัดรูปแบบวันที่และเพื่อที่ฉันจะใช้dateคำสั่ง ตัวอย่างเช่น

echo '1.2.2017 23:40:00' | sed 's/\./\//g' | xargs -0 date '+%m.%d.%Y %T' -d

จะส่งออก

01.02.2017 23:40:00

คำสั่งในช่วงกลางมีการเปลี่ยนแปลงระยะเวลาในการทับสำหรับการป้อนข้อมูลลงในsed date -dตัวเลือกรูปแบบอนุญาตให้ใช้เอาต์พุตในเกือบทุกรูปแบบที่คุณต้องการ %mโดยเฉพาะอย่างยิ่งความประสงค์ศูนย์แผ่นเดือนซึ่งเป็นสิ่งที่ดูเหมือนว่าคุณกำลังพยายามที่จะทำ

ดังที่ Kusalananda ชี้ให้เห็น:

กะทัดรัดยิ่งขึ้น (วันที่ GNU และ Bash): date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'


2
รับได้สวย! กะทัดรัดยิ่งขึ้น (วันที่ GNU และ Bash):date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'
Kusalananda

เมื่อใดก็ตามที่ฉันมี Slashes ในรูปแบบของฉัน s|\.|/|gแต่ไม่มีท่อ: มิฉะนั้นตามที่ระบุไว้ข้างต้น: Nice catch, +1
Alex Stragies

2

กลยุทธ์ที่แตกต่างจากที่แสดงในคำตอบอื่น ๆ : คุณสามารถใช้ "." เป็นตัวคั่นฟิลด์

awk -F. '$1 < 10 {printf "0"} {print}' /tmp/in.txt

คุณสามารถเล่นกอล์ฟนี้เพื่อ:

awk -F. '$1<10{printf "0"}1' /tmp/in.txt

สำหรับ sed มีคำสั่งที่สั้นกว่านำเสนอในอีกคำตอบ (เยี่ยมมาก)


1
ทางเลือก: awk -F. '{print ($1<10?0$0:$0)}' file
George Vasiliou

1

ด้วยความใจเย็น ๆ มันอาจจะเป็น

sed 's/^\(.\)\.\(.*\)/0\1.\2/'

สิ่งนี้จะใช้^ในการยึดกับจุดเริ่มต้นของบรรทัดจากนั้นจับตัวอักขระเดี่ยวใด ๆ ในกลุ่มตามด้วยตัวอักษร.แล้วตามด้วยอย่างอื่น หากเราจับคู่ที่เราพิมพ์ a 0กลุ่มการจับภาพแรกของเรา (ตัวอักษรที่จุดเริ่มต้นของบรรทัด) จากนั้นเลือก.กลุ่มการจับภาพที่สองของเรา (ส่วนที่เหลือของบรรทัด)


ไม่จำเป็นเลยที่จะทำการจับภาพใด ๆ &เป็นเพื่อนของคุณ. ดูตัวอย่างของ Kusalananda
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@DennisWilliamson ไม่จำเป็น แต่เนื่องจากมีตัวอย่างอื่น ๆ อยู่แล้วนี่แสดงให้เห็นถึงคุณลักษณะอื่นของsedสิ่งที่อาจเป็นประโยชน์ในสถานการณ์อื่น ๆ ไม่ใช่แค่ปัญหานี้เท่านั้น
Eric Renouf
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.