การทำซ้ำ awk {n} ไม่ทำงาน


18

ฉันพยายามพิมพ์บรรทัดโดยใช้สัญลักษณ์การทำซ้ำ {n} แต่มันไม่ทำงาน สำหรับ. เช่นฉันต้องการพิมพ์ทุกบรรทัดที่มีความยาว 4 อักขระ

 awk '/^.{4}$/' test_data

รหัสด้านบนไม่ได้ทำการพิมพ์นั้นจะแก้ไขได้อย่างไรเพื่อที่ฉันจะสามารถใช้สัญลักษณ์ซ้ำได้? ฉันรู้ว่าทางเลือกเช่นawk '/^....$/' test_dataและawk 'length ==3 ' test_data


3
คุณใช้การกระจายแบบใด อันไหนเหรอ?
terdon

1
$ awk - รุ่น GNU Awk 3.1.7 $ cat / etc / redhat-release Red Hat Enterprise Linux Server รีลีส 6.7 (Santiago)
ผู้เรียนตลอดกาล

2
ฉันจะบอกว่าawk '/^.{4}+$/{print}' <<<$'foods\nbaarsz\nfooo' ตรงกับ 4 ตัวอักษร นอกจากนี้ตามที่คุณพูดถึงตัวเอง awk 'length($0) == 4' test_dataเข้ากันได้กับเกือบทุกawkรุ่น
Valentin Bajrami

4
ทำawk --re-interval '/^.{4}$/' test_data หรือawk --posix '/^.{4}$/' test_dataทำงาน
ขับขี่เหล็ก

ขอบคุณผู้ขับขี่เหล็ก นี่เป็นการแก้ไขปัญหาของฉัน upvoted ขอขอบคุณอีกครั้ง :)
ผู้เรียนตลอดกาล

คำตอบ:


19

ตามคู่มือผู้ใช้ GNU Awk: ประวัติคุณสมบัติการสนับสนุนสำหรับโอเปอเรเตอร์ช่วงนิพจน์ปกติถูกเพิ่มในเวอร์ชัน 3.0 แต่ในตอนแรกจำเป็นต้องใช้ตัวเลือกบรรทัดคำสั่งอย่างชัดเจน

ตัวเลือกบรรทัดคำสั่งใหม่:

  • ตัวเลือกบรรทัดคำสั่งใหม่:
    • ตัวเลือก --lint-old เพื่อเตือนเกี่ยวกับโครงสร้างที่ไม่พร้อมใช้งานในเวอร์ชัน 7 เวอร์ชันเดิมของ awk (ดู V7 / SVR3.1)
    • ตัวเลือก -m จาก BWK awk (ไบรอันยังคงอยู่ที่ห้องปฏิบัติการของเบลล์ในเวลานั้น) หลังจากนี้ถูกย้ายออกจากทั้ง awk และจากเพ่งพิศ
    • ตัวเลือก --re-interval เพื่อจัดทำนิพจน์ช่วงเวลาใน regexps (ดูตัวดำเนินการ Regexp)
    • ตัวเลือก - แบบดั้งเดิมถูกเพิ่มเป็นชื่อที่ดีขึ้นสำหรับ --compat (ดูตัวเลือก)

ในgawk4.0

การแสดงออกช่วงกลายเป็นส่วนหนึ่งของการแสดงออกปกติเริ่มต้น

เนื่องจากคุณใช้gawk3.x คุณจะต้องใช้

awk --re-interval '/^.{4}$/'

หรือ

awk --posix '/^.{4}$/'

หรือ (ขอบคุณ @ StéphaneChazelas) หากคุณต้องการโซลูชันที่พกพาได้ให้ใช้

POSIXLY_CORRECT=anything awk '/^.{4}$/'

(ตั้งแต่--posixหรือ--re-intervalอาจทำให้เกิดข้อผิดพลาดในawkการใช้งานอื่น ๆ)


ขอบคุณผู้ขับเหล็กสำหรับเวลาและความช่วยเหลือของคุณ โหวตขึ้นและได้รับการยอมรับว่าเป็นคำตอบ
Forever Learner

4
มันจะดีกว่าที่จะใช้POSIXLY_CORRECT=anything awk '/^.{4}/'เป็นที่ทำให้รหัสพกพา ( --posixหรือ--re-intervalจะทำให้เกิดข้อผิดพลาดในawkการใช้งานอื่น ๆ)
Stéphane Chazelas

สวัสดีStéphane Chazelas เมื่อฉันออกคำสั่ง $ POSIXLY_CORRECT = Anything awk '/^.{4}/' test_data มันพิมพ์ทุกบรรทัด จากนั้นฉันก็ตระหนักว่าไม่มีเงินดอลลาร์สุดท้ายหลังจากทำซ้ำ ขอบคุณสำหรับอินพุตของคุณ การอัพโหลดความคิดเห็นและโซลูชันของคุณ ขออภัยฉันเข้าใจผิดตั้งแต่แรกเพราะไม่จ่ายเงิน $ หลังจากทำซ้ำ
ผู้เรียนตลอดกาล

20

Eres ( ขยายการแสดงออกปกติที่ใช้โดยawkหรือegrep) {x,y}ตอนแรกไม่ได้มี มันถูกนำมาใช้ครั้งแรกใน BREs (ตามที่ใช้โดยgrepหรือsed) แต่ด้วย\{x,y\}ไวยากรณ์ที่ไม่ได้ทำลายการพกพาไปข้างหลัง

แต่เมื่อมันถูกเพิ่มเข้าไปใน EREs ด้วย{x,y}ไวยากรณ์นั้นก็ทำให้การพกพาแบบย้อนกลับลดลงเนื่องจากfoo{2}RE ได้จับคู่บางสิ่งที่แตกต่างกันก่อนหน้านี้

ดังนั้นการใช้งานบางอย่างเลือกที่จะไม่ทำ คุณจะพบว่า/bin/awk, /bin/nawkและ/bin/egrepบน Solaris ยังไม่ให้เกียรติมัน (คุณจำเป็นต้องใช้/usr/xpg4/bin/awkหรือ/usr/xpg4/bin/grep -E) เหมือนกันawkและnawkบน FreeBSD (อิงจากการawkบำรุงรักษาโดย Brian Kernighan ( kในawk))

สำหรับ GNUawkจนกระทั่งเมื่อไม่นานมานี้ (เวอร์ชั่น 4.0) คุณต้องโทรหาPOSIXLY_CORRECT=anything awk '/^.{4}$/'เพื่อให้เกียรติ ยังคงไม่ได้ให้เกียรติมันmawk

โปรดทราบว่าผู้ประกอบการที่เป็นน้ำตาล syntactic เท่านั้น .{3,5}สามารถเขียนได้เสมอ....?.?เช่น (แน่นอนว่า{3,5}เป็นที่ชัดเจนมากขึ้นและเทียบเท่า(foo.{5,9}bar){123,456}จะเลวร้ายยิ่งกว่า)


ขอขอบคุณStéphane Chazelas อีกครั้ง ขออภัยฉันไม่ดีฉันไม่สามารถเข้าใจคำตอบของคุณในตอนแรก ขอบคุณมากและ upvoted
ผู้เรียนตลอดกาล

6

ใช้งานได้ตามที่คาดไว้กับ GNU awk(gawk):

$ printf 'abcd\nabc\nabcde\n' | gawk '/^.{4}$/'
abcd

แต่ล้มเหลวด้วยmawkซึ่งอยู่ใกล้กับ POSIX awkและ AFAIK เป็นค่าเริ่มต้นในระบบ Ubuntu:

$ printf 'abcd\nabc\nabcde\n' | mawk '/^.{4}$/'
$ ## prints nothing

ดังนั้นวิธีการแก้ปัญหาที่เรียบง่ายที่จะใช้แทนgawk สัญกรณ์ไม่ได้เป็นส่วนหนึ่งของ (ขั้นพื้นฐานการแสดงออกปกติ) ไวยากรณ์ POSIX BRE นั่นคือเหตุผลที่ล้มเหลวที่นี่ด้วย:awk{n}grep

$ printf 'abcd\nabc\nabcde\n' | grep '^.{4}$'
$

อย่างไรก็ตามเป็นส่วนหนึ่งของ ERE (นิพจน์ทั่วไปแบบขยาย):

$ printf 'abcd\nabc\nabcde\n' | grep -E '^.{4}$'
abcd

ฉันไม่ทราบว่า regex ใช้รสชาติแบบไหนmawkหรือ POSIX awkแต่ฉันเดาว่ามันคือ BRE. พวกเขาใช้รุ่นเก่าของ ERE ตามคำตอบของStéphane ไม่ว่าในกรณีใดก็ตามคุณเห็นได้ชัดว่าคุณใช้เวอร์ชันawkที่ไม่ได้ใช้ ERE หรืออินพุตของคุณไม่มีบรรทัดที่มีอักขระ 4 ตัว สิ่งนี้อาจเกิดขึ้นเนื่องจากช่องว่างที่คุณไม่เห็นหรือยูนิโค้ดร่ายมนตร์เป็นต้น


สวัสดี terdon ฉันต้องการพิมพ์บรรทัดที่มีความยาว 4 อักขระ ไม่ใช่อักขระสี่ตัวแรกของบรรทัด ตัวอย่างเช่น $ grep -E '^. {4} $' test_data จะทำงานได้ แต่จะไม่ทำงานกับ awk
ผู้เรียนตลอดกาล

@CppLearner ใช่นั่นคือสิ่งที่ฉันทำที่นี่ คุณหมายถึงอะไร
terdon

@CppLearner โซลูชันของ @ terdon จะพิมพ์เฉพาะบรรทัดที่มีความยาว 4 อักขระ แต่ถ้าคุณสนใจแค่ความยาวบรรทัดคุณควรใช้length($0)ซึ่งมีประสิทธิภาพมากกว่า regexes
Stephen Kitt

สวัสดี terdon คำตอบของผู้ขับรถบรรทุกเหล็กคือสิ่งที่ฉันต้องการ ขอบคุณที่สละเวลา. สวัสดีสตีเฟ่น Kitt ดังที่ฉันได้กล่าวถึงปัญหาฉันใช้ความยาวเป็นทางเลือกฉันสนใจในการรู้ว่าทำไม regex การทำซ้ำ {n} ไม่ทำงานจากความคิดเห็นของ steeldriver ฉันรู้ว่าฉันต้องใช้ตัวเลือกของ --re-interval หรือ --posix ขอบคุณที่สละเวลา.
ผู้เรียนตลอดกาล

1
mawkไม่ใกล้ POSIX จริงๆawkและไม่ใช้ BREs มันใช้ EREs แต่ไม่มีตัว{x,y}ดำเนินการ
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.