การแสดงออกปกติในสคริปต์ทุบตี


12

นี่เป็นครั้งแรกของฉันที่สคริปต์ทุบตีดังนั้นฉันอาจทำผิดพลาดง่าย

โดยทั่วไปฉันพยายามเขียนสคริปต์ที่ได้รับกลุ่มของผู้ใช้และหากพวกเขาอยู่ในกลุ่มที่แน่นอนก็จะเข้าสู่ระบบตามนั้น เห็นได้ชัดว่ามีฟังก์ชั่นเพิ่มเติม แต่ไม่มีจุดที่สร้างเมื่อฉันไม่สามารถใช้ regex ได้!

จนถึงตอนนี้ฉันมีสิ่งนี้:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

ทุกที่ที่ฉันลอง regex มันใช้งานได้ แต่ในสคริปต์ทุบตีมันเท่านั้นที่เคยออกผลลัพธ์เป็นตามด้วย$groups No matchดังนั้นใครบางคนสามารถบอกฉันว่ามีอะไรผิดปกติกับมัน?


1
อะไรทำให้คุณคิดว่ามีอะไรผิดปกติกับมัน?
จัดการ

1
@jrdnhannah จากนั้นลองสร้าง regexp เป้าหมายของคุณใหม่ช้าๆนัดแรก^([a-zA-Z0-9\-_]+)จากนั้นจึงเพิ่มลำไส้ใหญ่และอื่น ๆ ... คุณควรจะรู้ในไม่ช้าว่าปัญหาอยู่ที่ไหน
เตอร์

2
เหมือนกันที่นี่กับทุบตี 4.2.45 หนีการขีดล่างได้รับการแก้ไข แปลก. @jrdnhannah คุณช่วยเขียนมันขึ้นมาเป็นคำตอบและยอมรับมันได้ไหม?
terdon

1
เนื่องจากฉันเพิ่งสมัครใช้งาน Unix SE เท่านั้นฉันจึงต้องรอ 8 ชั่วโมงก่อนตอบคำถามของฉันเอง ยินดีที่จะทำเครื่องหมายว่าตอบถ้าคนอื่นทำ
jrdn

4
@terdon ทุบตีเพียงแค่เรียกฟังก์ชั่น regex ของ libc อาจ ดังนั้นขึ้นอยู่กับเวอร์ชัน libc ไม่ใช่เวอร์ชัน bash ดูคำตอบของฉัน ... (หรืออาจจะเป็นลำดับการเรียงที่คุณใช้อยู่)
Derobert

คำตอบ:


13

จากman 7 regex:

การแสดงออกวงเล็บคือรายการของตัวละครที่อยู่ใน "[]" ...

…หากต้องการรวมตัวอักษร '-' ให้เป็นตัวอักษรตัวแรกหรือตัวสุดท้าย…. [A] ll อักขระพิเศษอื่น ๆ รวมถึง '\' จะสูญเสียความสำคัญเป็นพิเศษในนิพจน์วงเล็บเหลี่ยม

ลองใช้ regexp ด้วย egrep จะทำให้เกิดข้อผิดพลาด:

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

นี่เป็นเวอร์ชั่นที่ง่ายกว่าซึ่งมีข้อผิดพลาดด้วย:

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

เนื่องจาก\ไม่ใช่พิเศษนั่นคือช่วงเหมือนที่[a-z]จะเป็น คุณต้องทำให้-ท้ายที่สุดเช่น[_-]หรือ:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

สิ่งนี้จะทำงานได้โดยไม่คำนึงถึงเวอร์ชัน libc ของคุณ (ใน egrep หรือ bash)

แก้ไข:สิ่งนี้ขึ้นอยู่กับการตั้งค่าภาษาของคุณด้วย manpage เตือนเกี่ยวกับสิ่งนี้:

ช่วงนั้นขึ้นอยู่กับการเรียงลำดับมากและโปรแกรมแบบพกพาควรหลีกเลี่ยงการพึ่งพา

ตัวอย่างเช่น:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

แน่นอนแม้ว่ามันจะไม่ผิดพลาด แต่ก็ไม่ได้ทำสิ่งที่คุณต้องการ:

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

มันเป็นช่วงซึ่งใน ASCII รวม\, [, และ^_


น่าสนใจ ฉันegrepให้ไม่มีข้อผิดพลาดเพียงแค่จับคู่อย่างถูกต้อง
จัดการ

@manatwork ลำดับการเปรียบเทียบของคุณอาจจะช่วยให้ช่วง ....
derobert

ฉันไม่ค่อยรู้เรื่องการเปรียบเทียบ คุณหมายถึงนี้LC_COLLATE="en_US.UTF-8"?
จัดการ

@ manatwork ฉันได้แก้ไขคำถามเพื่อยกตัวอย่าง โปรดทราบว่าระบบของคุณอาจแตกต่างกันออกไปเนื่องจากบางครั้งลำดับการเรียง (เรียงลำดับ) เหล่านั้นจะเปลี่ยนไป
Derobert

1
@manatwork ตกลงมันฉันเกือบจะยื่นรายงานข้อผิดพลาดก่อนที่ผมสังเกตเห็นความพยายามที่จะหลบหนี-...
derobert

4

กฎทั่วไปด้วย regexps (และข้อบกพร่องใด ๆ ในโค้ดที่มีขนาดใหญ่กว่า): ลดขนาดลงและสร้างใหม่ทีละขั้นตอนหรือใช้การแบ่งส่วน - สิ่งที่ใช้ได้ผลดีกว่าสำหรับคุณ

ในกรณีนี้ผู้ร้ายกลายเป็นขีดเส้นใต้ - การหลบหนีด้วยแบ็กสแลชทำให้การทำงานสำเร็จ

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