ใช้ sed เพื่อลบทั้งการเปิดและปิดวงเล็บเหลี่ยมรอบสตริง


18

ฉันใช้คำสั่งนี้ใน bash shell บน Ubuntu 12.04.1 LTS ฉันพยายามที่จะลบทั้งตัวละคร[และ]ตัวละครในฉากที่ตกเช่นเดียวโดยไม่ต้องไปปฎิบัติซ้ำอีกครั้ง

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

~$ echo '[123]' | sed 's/[\[\]]//'
[123]

สิ่งที่ฉันพยายามทำให้สำเร็จในที่สุดคือการกำหนดอะไรก็ตามระหว่างวงเล็บเหลี่ยมให้ตัวแปร bash สำหรับใช้ที่อื่นในสคริปต์ทุบตีของฉันดังนั้นหากมีวิธีที่ดีกว่าในการบรรลุเป้าหมายนั้น (โดยใช้ awk หรืออาจ?) โปรดแจ้งให้เราทราบ .
Xhantar

2
เพียงแค่เพิ่มความคิดเห็น: คุณสามารถใช้คุณสมบัติ PE ของ bash ใน: str='[123]'; str1=${str/\[/}; str2=${str1/\]}; echo $str2
Valentin Bajrami

1
@ val0x00ff - การแทนที่ทุบตีบริสุทธิ์ .. ขอบคุณ! :) เรียนรู้สิ่งใหม่ ๆ
Xhantar

คำตอบ:


24

นี่เป็นเรื่องง่ายถ้าคุณทำตามคู่มืออย่างระมัดระวังสมาชิกทุกคนในคลาสตัวละครจะสูญเสียความหมายพิเศษ (ยกเว้นบางประการ) และ] สูญเสียความหมายพิเศษของมันหากมันถูกวางไว้ก่อนในรายการ ลอง:

$ echo '[123]' | sed 's/[][]//g'
123
$

สิ่งนี้พูดว่า:

  1. ภายใน[brackets] ด้านนอกให้แทนที่อักขระที่รวมใด ๆ ได้แก่ :
    • ] และ
    • [
  2. แทนที่ใด ๆ ของพวกเขาโดยสตริงที่ว่างเปล่า - เพราะฉะนั้นสตริงทดแทนที่ว่างเปล่า//,
  3. แทนที่พวกเขาทุกที่ ( ทั่วโลก ) - gเพราะฉะนั้นสุดท้าย

อีกครั้ง] จะต้องเป็นคนแรกในชั้นเรียนเมื่อใดก็ตามที่มันจะรวม


11

ฉันไม่แน่ใจว่าทำไมถึงไม่ได้ผล แต่เป็นเช่นนี้:

echo '[123]' | sed 's/\(\[\|\]\)//g'

หรือสิ่งนี้:

echo '[123]' | sed -r 's/(\[|\])//g'

คุณยังสามารถลองใช้วิธีอื่นและจับคู่สตริงภายในวงเล็บ (สมมติว่าสตริงสามารถจับคู่ได้ง่ายและไม่ได้กำหนดโดยวงเล็บ):

echo '[123]' | egrep -o "[0-9]+"

ฉันมีปัญหาเดียวกันกับ regex ดั้งเดิมของคุณโดยใช้grepดังนั้นฉันสงสัยว่านี่ไม่ใช่แค่sedสิ่งเดียว

น่าแปลกที่สิ่งเหล่านี้ให้ผลลัพธ์ที่แตกต่าง แต่หนึ่งในนั้นตรงกับสิ่งที่คุณต้องการ:

echo '[123]' | egrep -o '[^][]+'
123

echo '[123]' | egrep -o '[^[]]+'
3]

ใช้สิ่งนี้กับต้นฉบับของคุณsed(และเพิ่ม/gตัวแก้ไขเพื่อให้ลบทั้งสองวงเล็บ):

echo '[123]' | sed 's/[][]//g'
123

วิธีที่ 3 ของคุณ (egrep -o ... ) ดูเหมือนว่าวิธีการแก้ปัญหาที่ดีที่สุดสำหรับปัญหาของฉัน ฉันจะมีจำนวนเต็มเพียงระหว่างวงเล็บเหลี่ยม (และขอโทษฉันควรได้กล่าวถึงในคำถามของฉัน) ดังนั้นฉันไม่ควรวิ่งเข้าไปในสิ่งแปลกประหลาดที่ฉันคิดว่า ขอบคุณ!
Xhantar

3
คุณยังสามารถใช้tr: echo '[123]' | tr -d '[]'- หลีกเลี่ยงความสับสนใน regexp เกี่ยวกับการหลบหนี
James O'Gorman

@James O'Gorman - น่าสนใจ ด้วยเหตุผลบางอย่างฉันคิดว่าtrสามารถแปลได้สูงสุดตัวอักษรครั้งละหนึ่งตัวเท่านั้น แต่ฉันคิดผิด ขอบคุณ!
Xhantar

4

หากต้องการลบทุกอย่างก่อนและหลังวงเล็บ:

$ echo '[123]' | sed 's/.*\[//;s/\].*//;'
123

หากข้อมูลของคุณเป็นเช่นนี้หมายถึงการเริ่มต้นและสิ้นสุดด้วยวงเล็บเหลี่ยมเสมอ

$ echo '[123]' | sed 's/.//;s/.$//;'
123

ข้อมูลที่ฉันทำงานด้วยจะเริ่มต้นและสิ้นสุดด้วยวงเล็บเหลี่ยมเสมอ ฉันยังต้องการทราบว่าเพราะเหตุใดโซลูชันของฉันจึงไม่ทำงาน ความคิดใด ๆ และมีวิธีการทำเช่นนี้โดยไม่ระบุ 2x regex หรือไม่
Xhantar

1
@Guru โซลูชันนี้ใช้งานได้จากฉันและสำหรับ Xhantar นี่เป็นคำตอบที่ล่าช้า แต่สิ่งที่ฉันเห็นได้จากโค้ดของคุณและคู่มือผู้ใช้ Bash Beginners ที่ tldp.org คุณพยายามค้นหาหลายครั้งและแทนที่ด้วยหนึ่งรายการสำหรับ '[' และอีกอันสำหรับ ']' ซึ่งไม่สามารถใช้งานได้เพื่อแยกการค้นหาที่แตกต่างกันสองรายการและแทนที่ให้ใช้ ";" หรือตัวเลือก -e 's / <search> / <replace> / g; s / <search> / <replace> / g 'หรือ sed -e' s / <search> / <replace> / g '-e' s / <search> / <replace> / g '
ArunMKumar

1

หากคุณมีสตริงที่ซับซ้อนกว่าเช่น 'abcdef [123] ghijk' คุณสามารถใช้คำสั่ง bash ภายใน 'ตัด' เพื่อแยกข้อความระหว่างวงเล็บเหลี่ยมเท่านั้น:

$ echo 'abcdef[123]ghijk' | cut -d '[' -f 2 | cut -d ']' -f 1
123

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