ตัวแก้ไขสตรีม - สตริง

แทนคำสั่ง

การดำเนินการแทนข้อความเช่น "ค้นหาและแทนที่" เป็นเรื่องปกติในโปรแกรมแก้ไขข้อความใด ๆ ในส่วนนี้เราแสดงให้เห็นว่า SED ทำการแทนที่ข้อความอย่างไร ให้ด้านล่างนี้คือไวยากรณ์ของคำสั่งการแทนที่

[address1[,address2]]s/pattern/replacement/[flags]

ที่นี่ address1 และ address2คือที่อยู่เริ่มต้นและสิ้นสุดตามลำดับซึ่งอาจเป็นหมายเลขบรรทัดหรือสตริงรูปแบบก็ได้ ที่อยู่ทั้งสองนี้เป็นพารามิเตอร์ทางเลือก รูปแบบคือข้อความที่เราต้องการแทนที่ด้วยสตริงแทนที่ นอกจากนี้เราสามารถระบุแฟล็กเสริมด้วย SED

ในไฟล์ books.txt เราได้ใช้ลูกน้ำ (,) เพื่อแยกแต่ละคอลัมน์ ให้เราใช้แถบแนวตั้ง (|) เพื่อแยกแต่ละคอลัมน์ ในการดำเนินการนี้ให้แทนที่เครื่องหมายจุลภาค (,) ด้วยแถบแนวตั้ง (|)

[jerry]$ sed 's/,/ | /' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

1) A Storm of Swords | George R. R. Martin, 1216 
2) The Two Towers | J. R. R. Tolkien, 352 
3) The Alchemist | Paulo Coelho, 197 
4) The Fellowship of the Ring | J. R. R. Tolkien, 432 
5) The Pilgrimage | Paulo Coelho, 288 
6) A Game of Thrones | George R. R. Martin, 864

หากคุณสังเกตอย่างรอบคอบจะมีเพียงเครื่องหมายจุลภาคตัวแรกเท่านั้นที่ถูกแทนที่และตัวที่สองจะยังคงอยู่เหมือนเดิม ทำไม? ทันทีที่รูปแบบตรงกัน SED จะแทนที่ด้วยสตริงแทนที่และย้ายไปยังบรรทัดถัดไป โดยค่าเริ่มต้นจะแทนที่เฉพาะเหตุการณ์แรกเท่านั้น ในการแทนที่เหตุการณ์ทั้งหมดให้ใช้ global flag (g) กับ SED ดังนี้:

[jerry]$ sed 's/,/ | /g' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

1) A Storm of Swords | George R. R. Martin | 1216 
2) The Two Towers | J. R. R. Tolkien | 352 
3) The Alchemist | Paulo Coelho | 197 
4) The Fellowship of the Ring | J. R. R. Tolkien | 432 
5) The Pilgrimage | Paulo Coelho | 288 
6) A Game of Thrones | George R. R. Martin | 864

ตอนนี้การเกิดขึ้นทั้งหมดของเครื่องหมายจุลภาค (,) จะถูกแทนที่ด้วยแถบแนวตั้ง (|)

เราสามารถสั่งให้ SED ทำการแทนที่ข้อความได้ก็ต่อเมื่อการจับคู่รูปแบบสำเร็จ ตัวอย่างต่อไปนี้แทนที่เครื่องหมายจุลภาค (,) ด้วยแถบแนวตั้ง (|) เฉพาะเมื่อเส้นมีรูปแบบ The Pilgrimage

[jerry]$ sed '/The Pilgrimage/ s/,/ | /g' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage | Paulo Coelho | 288 
6) A Game of Thrones, George R. R. Martin, 864

นอกจากนี้ SED ยังสามารถแทนที่รูปแบบที่เกิดขึ้นเฉพาะได้ ให้เราแทนที่เฉพาะอินสแตนซ์ที่สองของลูกน้ำ (,) ด้วยแถบแนวตั้ง (|)

[jerry]$ sed 's/,/ | /2' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

1) A Storm of Swords, George R. R. Martin | 1216 
2) The Two Towers, J. R. R. Tolkien | 352 
3) The Alchemist, Paulo Coelho | 197 
4) The Fellowship of the Ring, J. R. R. Tolkien | 432 
5) The Pilgrimage,Paulo Coelho | 288 
6) A Game of Thrones, George R. R. Martin  | 864

ในตัวอย่างข้างต้นตัวเลขท้ายคำสั่ง SED (หรือที่ตำแหน่งของแฟล็ก) หมายถึงเหตุการณ์ที่ 2

SED มีคุณสมบัติที่น่าสนใจ หลังจากทำการเปลี่ยนตัว SED จะมีตัวเลือกให้แสดงเฉพาะบรรทัดที่เปลี่ยนแปลง เพื่อจุดประสงค์นี้ SED ใช้ไฟล์pธงซึ่งหมายถึงการพิมพ์ ตัวอย่างต่อไปนี้แสดงเฉพาะบรรทัดที่เปลี่ยนแปลง

[jerry]$ sed -n 's/Paulo Coelho/PAULO COELHO/p' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288

เราสามารถจัดเก็บบรรทัดที่เปลี่ยนแปลงไว้ในไฟล์อื่นได้เช่นกัน เพื่อให้ได้ผลลัพธ์นี้ให้ใช้ไฟล์wธง. ตัวอย่างต่อไปนี้แสดงวิธีการทำ

[jerry]$ sed -n 's/Paulo Coelho/PAULO COELHO/w junk.txt' books.txt

เราใช้คำสั่ง SED เดียวกัน ให้เราตรวจสอบเนื้อหาของไฟล์junk.txt ไฟล์.

[jerry]$ cat junk.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288

ในการดำเนินการแทนแบบไม่คำนึงถึงขนาดตัวพิมพ์ให้ใช้แฟล็ก i ซึ่งแสดงถึงการละเว้นตัวพิมพ์ ตัวอย่างต่อไปนี้ทำการแทนที่แบบไม่คำนึงถึงขนาดตัวพิมพ์

[jerry]$ sed  -n 's/pAuLo CoElHo/PAULO COELHO/pi' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288

จนถึงตอนนี้เราใช้เฉพาะอักขระ foreslash (/) เป็นตัวคั่น แต่เรายังสามารถใช้แถบแนวตั้ง (|), ที่เครื่องหมาย (@), คาเร็ท (^), เครื่องหมายอัศเจรีย์ (!) เป็นตัวคั่น ตัวอย่างต่อไปนี้แสดงวิธีใช้อักขระอื่นเป็นตัวคั่น

สมมติว่าคุณต้องเปลี่ยนเส้นทาง /bin/sed ด้วย /home/jerry/src/sed/sed-4.2.2/sed. ดังนั้นคำสั่ง SED ของคุณมีลักษณะดังนี้:

[jerry]$ echo "/bin/sed" | sed 's/\/bin\/sed/\/home\/jerry\/src\/sed\/sed-4.2.2\/sed/'

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

/home/jerry/src/sed/sed-4.2.2/sed

เราสามารถทำให้คำสั่งนี้อ่านง่ายและเข้าใจง่ายขึ้น ให้เราใช้แถบแนวตั้ง (|) เป็นตัวคั่นและดูผลลัพธ์

[jerry]$ echo "/bin/sed" | sed 's|/bin/sed|/home/jerry/src/sed/sed-4.2.2/sed|'

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

/home/jerry/src/sed/sed-4.2.2/sed

แน่นอน! เราได้ผลลัพธ์เดียวกันและไวยากรณ์ก็อ่านง่ายขึ้น ในทำนองเดียวกันเราสามารถใช้เครื่องหมาย "at" (@) เป็นตัวคั่นได้ดังนี้:

[jerry]$ echo "/bin/sed" | sed 's@/bin/sed@/home/jerry/src/sed/sed-4.2.2/sed@'

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

/home/jerry/src/sed/sed-4.2.2/sed

นอกจากนี้เราสามารถใช้คาเร็ต (^) เป็นตัวคั่นได้

[jerry]$ echo "/bin/sed" | sed 's^/bin/sed^/home/jerry/src/sed/sed-4.2.2/sed^'

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

/home/jerry/src/sed/sed-4.2.2/sed

เรายังสามารถใช้เครื่องหมายอัศเจรีย์ (!) เป็นตัวคั่นได้ดังนี้:

[jerry]$ echo "/bin/sed" | sed 's!/bin/sed!/home/jerry/src/sed/sed-4.2.2/sed!'

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

/home/jerry/src/sed/sed-4.2.2/sed

โดยทั่วไปแล้วแบ็กสแลช (/) จะใช้เป็นตัวคั่น แต่บางครั้งการใช้ตัวคั่นอื่น ๆ ที่รองรับกับ SED จะสะดวกกว่า

การสร้าง Substring

เราได้เรียนรู้คำสั่งทดแทนที่ทรงพลัง ให้เราดูว่าเราสามารถค้นหาสตริงย่อยจากข้อความที่ตรงกันได้หรือไม่ ให้เราเข้าใจวิธีการทำด้วยความช่วยเหลือของตัวอย่าง

ให้เราพิจารณาข้อความต่อไปนี้:

[jerry]$ echo "Three One Two"

สมมติว่าเราต้องจัดให้เป็นลำดับ หมายความว่าควรพิมพ์หนึ่งก่อนจากนั้นสองและสุดท้ายสาม หนึ่งซับต่อไปนี้จำเป็น

echo "Three One Two" | sed 's|\(\w\+\) \(\w\+\) \(\w\+\)|\2 \3 \1|'

โปรดทราบว่าในตัวอย่างข้างต้นแถบแนวตั้ง (|) ถูกใช้เป็นตัวคั่น

ใน SED สามารถระบุสตริงย่อยได้โดยใช้ตัวดำเนินการจัดกลุ่มและต้องนำหน้าด้วยอักขระหลีกเช่น \( และ \).

\wเป็นนิพจน์ทั่วไปที่จับคู่ตัวอักษรตัวเลขหรือขีดล่างและ "+" ใช้เพื่อจับคู่อักขระมากกว่าหนึ่งตัว กล่าวอีกนัยหนึ่งคือนิพจน์ทั่วไป\(\w\+\) จับคู่คำเดี่ยวจากสตริงอินพุต

ในสตริงอินพุตมีสามคำคั่นด้วยช่องว่างดังนั้นจึงมี threeนิพจน์ทั่วไปคั่นด้วยช่องว่าง นิพจน์ทั่วไปแรกเก็บคำแรกคือสามคำที่สองเก็บคำOneและที่สามเก็บคำ Two

สตริงย่อยเหล่านี้ถูกอ้างถึงโดย \N,โดยที่ N คือหมายเลขสตริงย่อย ดังนั้น\2 พิมพ์สตริงย่อยที่สองกล่าวคือ One; \3 พิมพ์สตริงย่อยที่สามกล่าวคือ Two; และ \1 พิมพ์สตริงย่อยแรกกล่าวคือ Three

ให้เราแยกคำเหล่านี้ด้วยลูกน้ำ (,) และแก้ไขนิพจน์ทั่วไปตามนั้น

[jerry]$ echo "Three,One,Two" | sed 's|\(\w\+\),\(\w\+\),\(\w\+\)|\2,\3,\1|'

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

One,Two,Three

โปรดทราบว่าขณะนี้มีเครื่องหมายจุลภาค (,) แทนช่องว่างในนิพจน์ทั่วไป

String Replacement Flags (GNU SED เท่านั้น)

ในส่วนก่อนหน้านี้เราได้เห็นตัวอย่างบางส่วนของคำสั่งการแทนที่ GNU SED มีลำดับการหลีกเลี่ยงพิเศษซึ่งสามารถใช้ในสตริงการแทนที่ โปรดทราบว่าแฟล็กการแทนที่สตริงเหล่านี้เป็นค่าเฉพาะของ GNU และอาจใช้กับ SED ตัวแปรอื่นไม่ได้ ในที่นี้เราจะพูดถึงแฟล็กการเปลี่ยนสตริง

  • \ L: เมื่อระบุ \ L ในสตริงแทนที่จะถือว่าอักขระที่เหลือทั้งหมดของคำหลัง \ L เป็นอักขระตัวพิมพ์เล็ก ตัวอย่างเช่นอักขระ "ULO" จะถือว่าเป็นอักขระตัวพิมพ์เล็ก

[jerry]$ sed -n 's/Paulo/PA\LULO/p' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

3) The Alchemist, PAulo Coelho, 197
5) The Pilgrimage, PAulo Coelho, 288
  • \ u: เมื่อระบุ \ u ในสตริงการแทนที่จะถือว่าอักขระที่อยู่หลัง \ u เป็นอักขระตัวพิมพ์ใหญ่ ในตัวอย่างต่อไปนี้ \ u ใช้ก่อนอักขระ 'a' และ 'o' ดังนั้น SED จึงถือว่าอักขระเหล่านี้เป็นตัวอักษรตัวพิมพ์ใหญ่

[jerry]$ sed -n 's/Paulo/p\uaul\uo/p' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

3) The Alchemist, pAulO Coelho, 197 
5) The Pilgrimage, pAulO Coelho, 288
  • \ U: เมื่อระบุ \ U ในสตริงแทนที่จะถือว่าอักขระที่เหลือทั้งหมดของคำหลัง \ U เป็นอักขระตัวพิมพ์ใหญ่

[jerry]$ sed -n 's/Paulo/\Upaulo/p' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

3) The Alchemist, PAULO Coelho, 197 
5) The Pilgrimage, PAULO Coelho, 288
  • \ E: ควรใช้แฟล็กนี้กับ \ L หรือ \ U หยุดการแปลงที่เริ่มต้นโดยแฟล็ก \ L หรือ \ U ในตัวอย่างต่อไปนี้เฉพาะคำแรกเท่านั้นที่จะถูกแทนที่ด้วยตัวอักษรตัวพิมพ์ใหญ่

[jerry]$ sed -n 's/Paulo Coelho/\Upaulo \Ecoelho/p' books.txt

ในการรันโค้ดด้านบนคุณจะได้ผลลัพธ์ดังต่อไปนี้:

3) The Alchemist, PAULO coelho, 197 
5) The Pilgrimage, PAULO coelho, 288