คุณจะบันทึก regex ที่ซับซ้อนสำหรับการใช้ซ้ำหลายครั้งใน sed ได้อย่างไร


12

ในการใช้sedฉันมักจะสร้าง regexes ที่ค่อนข้างซับซ้อนและซับซ้อนซึ่งฉันต้องจับคู่สองครั้งในไฟล์ มีวิธีให้ฉันบันทึก regex นี้และเพียงแค่อ้างอิงสองครั้งหรือไม่

บางทีสิ่งที่มีลักษณะเช่นนี้?

sed ' complicated_regex=/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+$/
s/complicated_regex:complicated_regex/simple-output/
' my_file

อัปเดต: คำตอบนำเสนอวิธีการใช้ตัวแปร bash มันใช้งานไม่ได้ test.txtที่กำหนด

#test.txt
foo bar
bar foo

และสคริปต์

#!/bin/bash

VALUE='foo \([a-z]\+\)'

sed 's/"${VALUE}"/foo happy \1/' test.txt

สิ่งนี้ควรสร้างผลลัพธ์

foo happy bar
bar foo

แต่ฉันได้รับข้อผิดพลาดแทน

sed: -e expression #1, char 24: invalid reference \1 on `s' command's RHS

หากคุณใช้ Perl คุณสามารถอ้างอิงส่วนก่อนหน้าของนิพจน์ภายในนิพจน์ได้:perl -pe 's/^(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+:\1$/simple_output/' my_file
glenn jackman

1
เมื่อคุณพบบางสิ่งที่ซับซ้อนเกินกว่าจะล่อใจอย่าลังเลที่จะไปไกลหรือตื่นตกใจ
Gilles 'หยุดชั่วร้าย'

2
@Cory: ตัวอย่างของคุณทำงานได้ดีถ้าคุณได้รับไวยากรณ์ที่ถูกต้อง คุณมี "$ ตัวแปร" ยังคงอยู่ใน 'คำพูดเดียว' ซึ่งซ่อนไว้จากการขยายตัวของเชลล์ที่คุณคาดหวัง ... มันควรจะเป็นsed 's/'"${VALUE}"'/foo happy \1/' test.txt
Peter.O

คำตอบ:


7

คุณสามารถใช้ตัวแปรเชลล์:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{$i}})?)+'
sed s/^"$complicated_regex":"$complicated_regex"\$/'simple-output'/ my_file

ฉันไม่แน่ใจเกี่ยวกับสิ่งที่คุณหมายถึง$iแต่คุณอาจต้องใส่มันนอกคำพูดเดียว:

complicated_regex='(([a-f0-9]{32})+([a-zA-Z0-9=]{{'"$i"'}})?)+'

แน่นอนว่ามันใช้งานได้ก็ต่อเมื่อsedคำสั่งถูกเรียกใช้จากเชลล์ แต่มีวิธีแก้ปัญหาที่คล้ายกันกับภาษาการเขียนโปรแกรมเกือบทั้งหมด (และฉันคิดว่ามันเป็นไปไม่ได้ที่จะใช้ตัวแปรภายในsed)
Stéphane Gimenez

การบริหารทรัพยากรมนุษย์ เมื่อลองทำสิ่งนี้ดูเหมือนว่าการอ้างอิงกลับจะไม่สามารถใช้งานได้ s/$complicated_regex/\1/ให้ข้อผิดพลาดที่บอกว่าเป็นการอ้างอิงที่ไม่ถูกต้อง
Cory Klein

อาบางทีความผิดของฉันฉันคุ้นเคยกับการเปลี่ยนตัวแปร zsh ดูคำตอบที่อัปเดต
Stéphane Gimenez

คุณจะต้องลบแองเคอจากตัวแปรและใส่ไว้ในสคริปต์ sed นี้:sed "s/^${complicated_regex}:${complicated_regex}\$/simple-output/" my_file
เกล็น Jackman

ดุจ! ใช่ฉันลืมที่จะตรวจสอบว่าฉันได้รับการเชื่อมโยง regex ที่ถูกต้อง :-)
Stéphane Gimenez

0

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

ตัวอย่างโค้ดทั้งหมดต่อไปนี้จะถือว่า: VALUE='foo \([a-z]\+\)'

ต่อไปนี้เสียรหัสล้มเหลวเนื่องจากตัวแปรVALUEจะไม่ได้ขยาย:

sed 's/"${VALUE}"/foo happy \1/' test.txt

ต่อไปนี้เสียรหัสล้มเหลวเนื่องจากทับขวาบน\1ได้รับการกินโดยเปลือก (เพราะมันอยู่ในคำพูดคู่มากกว่าราคาเดียว) ก่อนที่จะsedเคยเห็นมัน:

sed "s/${VALUE}/foo happy \1/" test.txt

รหัสต่อไปนี้ทำงานตามที่คาดไว้:

sed 's/'"${VALUE}"'/foo happy \1/' test.txt

รหัสต่อไปนี้ยังใช้งานได้:

sed "s/${VALUE}/foo happy \\1/" test.txt

ดังนั้นต่อไปนี้:

sed s/"${VALUE}"/foo\ happy\ \\1/ test.txt

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

sed 's/'"${VALUE}"'/foo happy \1/' test.txt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.