Bash = ~ regex และ https://regex101.com/


12

ใช้https://regex101.com/ฉันสร้างนิพจน์ทั่วไปเพื่อส่งคืนที่อยู่ IP แรกในสตริง

นิพจน์ทั่วไป:

(?:\d{1,3}\.)+(?:\d{1,3})

RegExp รวมถึงตัวคั่น:

/(?:\d{1,3}\.)+(?:\d{1,3})/

ด้วยสตริงทดสอบต่อไปนี้:

eu-west                       140.243.64.99 

ส่งคืนการจับคู่แบบเต็มของ:

140.243.64.99

ไม่ว่าฉันจะลองกับสมอหรือไม่ก็ตามสคริปต์ทุบตีต่อไปนี้จะไม่ทำงานกับนิพจน์ทั่วไปที่สร้างขึ้น

temp="eu-west                       140.243.64.99            "
regexp="(?:\d{1,3}\.)+(?:\d{1,3})"
if [[ $temp =~ $regexp ]]; then
  echo "found a match"
else
  echo "No IP address returned"
fi

3
ที่ดูเหมือน Perl ปกติสำหรับฉัน Bash ไม่รองรับสิ่งนั้น
Kusalananda

1
=~ผู้ประกอบการจะกล่าวถึงที่นี่ในคู่มือที่มันเขียนใช้ทุบตี "ขยายการแสดงออกปกติ" regexes ขยายอธิบายไว้ในregex(7)หน้าคนและในเวลาสั้น ๆ สรุปได้ที่นี่
เกล็นแจ็คแมน

คำตอบ:


15

\dเป็นวิธีที่ไม่เป็นมาตรฐานสำหรับการพูดว่า "ตัวเลขใด ๆ " ฉันคิดว่ามันมาจาก Perl และภาษาและยูทิลิตี้อื่น ๆ อีกมากมายรองรับ REs ที่เข้ากันได้กับ Perl (PCRE) เช่นกัน (และเช่น GNU grep 2.27 ในการยืดเดเบียนสนับสนุน\wตัวอักษรที่คล้ายกันแม้ในโหมดปกติ)

ทุบตีไม่สนับสนุน\dแม้ว่าดังนั้นคุณจำเป็นต้องใช้อย่างชัดเจนหรือ[0-9] [[:digit:]]เช่นเดียวกันสำหรับกลุ่มที่ไม่ได้จับภาพ(?:..)ให้ใช้เพียง(..)แทน

สิ่งนี้ควรพิมพ์match:

temp="eu-west                       140.243.64.99            "
regexp="([0-9]{1,3}\.)+([0-9]{1,3})"
[[ $temp =~ $regexp ]] && echo match

2
ไม่ GNU ของคุณgrepสนับสนุน\dโดยไม่-P?
Stéphane Chazelas

@ StéphaneChazelasขออภัยไม่แน่นอน มันรองรับ\wและ\bซึ่งฉันได้เรียนรู้จาก Perl ดังนั้นฉันจึงสับสน
ilkkachu

1
มันไม่ยุติธรรมเลยที่จะพูด\dหรือ PCRE นั้น "ไม่เป็นมาตรฐาน" เป็นมาตรฐานค่อนข้างแตกต่างจากนิพจน์ทั่วไปดั้งเดิมและนิพจน์ทั่วไปที่ขยายเพิ่ม
Daniel Farrell

1
@DanielFarrell มาตรฐานในกรณีนี้คือสิ่งที่ระบุ POSIX\dและมันก็ไม่ทราบเกี่ยวกับ แม้ว่าคุณจะถูกต้องใน PCRE นั้นเป็นมาตรฐานหรืออย่างน้อยก็กำหนดไว้อย่างดี ปัญหาที่น่ารำคาญคือว่า GNU grep (หรือ glibc) สนับสนุนบาง PCRE เหมือนอะตอมอย่างน้อย\wและ\sเมื่อแปล ERE และในบริบทที่พวกเขาเป็นอย่างมากเป็นที่ไม่เป็นมาตรฐาน การใช้ถ้อยคำของฉันอาจมาจากส่วนนั้นและความเข้าใจผิดที่\dสนับสนุน GNU ในทำนองเดียวกัน
ilkkachu

4

(:...)และ\dเป็นตัวดำเนินการนิพจน์ทั่วไปของ perl หรือ PCRE (เช่นใน GNU grep -P)

bashเพียง แต่สนับสนุนการขยายการแสดงผลปกติในขณะที่grep -Eยกเว้นว่าสำหรับ regexps ผ่านตัวอักษรในขณะที่[[ text =~ regexp-here ]]เมื่อเทียบกับเป็นผลมาจากการขยายตัว unquoted (ใน[[ text =~ $var ]]หรือ[[ test =~ $(printf '%s\n' 'regexp-here') ]]) ก็ จำกัด ให้ POSIX ขยายแสดงออกชุดคุณลักษณะปกติ

ดังนั้นแม้ในระบบที่ใช้grep -E '\d'งานได้ (GNU EREs ได้นำเข้าส่วนขยายบางส่วนจาก perl regexps เช่น\sเวอร์ชันในอนาคตอาจมี\dเช่นกัน) คุณต้องใช้:

regexp='\d'
[[ $text =~ $regexp ]]

ในbashการทำงาน ( [[ $text =~ \d ]]จะไม่)

สำหรับเชลล์ที่สนับสนุน PCREs คุณอาจต้องการใช้zshแทน:

set -o rematchpcre
[[ $text =~ '(?:\d{1,3}\.)+(?:\d{1,3})' ]]

ksh93 ยังสนับสนุนการใช้งานนิพจน์ทั่วไปของ perl ที่คล้ายกัน (ไม่เข้ากันได้อย่างเต็มที่) ในฐานะที่เป็นส่วนหนึ่งของการจับคู่รูปแบบ ที่นั่นคุณจะใช้:

regexp='~(P)(?:\d{1,3}\.)+(?:\d{1,3})'
[[ $text = $regexp ]]

(โปรดสังเกต=แทนคุณ=~จะต้องการใช้ตัวแปรชั่วคราวเนื่องจากเป็นบั๊กกี้เมื่อคุณไม่ต้องการ)


1

ไซต์regex101.comใช้ PCRE (ดูที่มุมซ้ายบน) เป็นค่าเริ่มต้นและขาดการสนับสนุนสำหรับไวยากรณ์ "ขยาย" ของ regex นั่นคือ "Perl Compatible Expresions ปกติ" ซึ่งมา (ตามที่สมเหตุสมผลที่คาดหวัง) จาก Perl

PCRE ได้รับการสนับสนุนโดยเครื่องมือบางอย่าง (เช่นgrep -P) ภายใต้เงื่อนไขบางประการ แต่การสนับสนุน bash regex ภายใน[[…]]สำนวนนั้นใช้สำหรับ regex แบบขยายเท่านั้น (เช่นgrep -E)

ใน Extended regex (?…)วงเล็บที่ไม่ใช่การดักจับไม่มีอยู่และ \ d หายไปเช่นกัน คุณต้องใช้ง่าย(…)และ[0-9]:

regexp="([0-9]{1,3}\.)+([0-9]{1,3})"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.