บทความนี้เป็นส่วนหนึ่งของซีรีส์เคล็ดลับและเทคนิค Unix Sed ที่ดำเนินต่อไป
ในบทความ sed ก่อนหน้าเราเรียนรู้ — sed printing, sed deletion, sed substitute, sed file write, และ sed multiple commands
ในบทความนี้ เราจะทบทวนวิธีแก้ปัญหาที่น่าสนใจกับคำสั่ง "s" substitute ใน sed พร้อมตัวอย่างปฏิบัติจริงหลายตัวอย่าง
I. Sed Substitution Delimiter
ตามที่อภิปรายในโพสต์ก่อนหน้า เราสามารถใช้ตัวคั่นที่แตกต่างกัน เช่น @ % | ; : ในคำสั่ง sed substitute
มาสร้างไฟล์ path.txt ก่อน ซึ่งจะใช้ในตัวอย่างทั้งหมดด้านล่าง
$ cat path.txt /usr/kbos/bin:/usr/local/bin:/usr/jbin:/usr/bin:/usr/sas/bin /usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin:/opt/omni/bin: /opt/omni/lbin:/opt/omni/sbin:/root/bin
ตัวอย่าง 1 – sed @ delimiter: แทนที่ /opt/omni/lbin เป็น /opt/tools/bin
เมื่อคุณแทนที่ path name ที่มี '/' คุณสามารถใช้ @ เป็นตัวคั่นแทน '/' ในตัวอย่าง sed ด้านล่าง ในบรรทัดสุดท้ายของไฟล์อินพุท /opt/omni/lbin ถูกเปลี่ยนเป็น /opt/tools/bin
$ sed 's@/opt/omni/lbin@/opt/tools/bin@g' path.txt /usr/kbos/bin:/usr/local/bin:/usr/jbin/:/usr/bin:/usr/sas/bin /usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin:/opt/omni/bin: /opt/tools/bin:/opt/omni/sbin:/root/bin
ตัวอย่าง 2 – sed / delimiter: แทนที่ /opt/omni/lbin เป็น /opt/tools/bin
เมื่อควรใช้ '/' ในการแทนที่ที่เกี่ยวกับ path name คุณต้อง escape '/' ในข้อมูลการแทนที่ ตามด้านล่าง ในตัวอย่าง sed นี้ delimiter '/' ถูก escape ในส่วน REGEXP และ REPLACEMENT
$ sed 's/\/opt\/omni\/lbin/\/opt\/tools\/bin/g' path.txt /usr/kbos/bin:/usr/local/bin:/usr/jbin/:/usr/bin:/usr/sas/bin /usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin:/opt/omni/bin: /opt/tools/bin:/opt/omni/sbin:/root/bin
II. Sed '&' รับสตริงที่จับคู่
ส่วนที่แน่นอนของบรรทัดอินพุตที่ Regular Expression จับคู่ แทนด้วย & ซึ่งสามารถใช้ในส่วน replacement ได้
ตัวอย่าง 1 – sed & Usage: แทนที่ /usr/bin/ เป็น /usr/bin/local
$ sed 's@/usr/bin@&/local@g' path.txt /usr/kbos/bin:/usr/local/bin:/usr/jbin/: /usr/bin/local:/usr/sas/bin /usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin/local:/opt/omni/bin: /opt/omni/lbin:/opt/omni/sbin:/root/bin
ในตัวอย่างข้างต้น '&' ในส่วน replacement จะแทนที่ด้วย /usr/bin ซึ่งเป็น pattern ที่จับคู่ และเพิ่มกับ /local ดังนั้นในเอาต์พุต ทุกครั้งที่เจอ /usr/bin จะถูกแทนที่ด้วย /usr/bin/local
ตัวอย่าง 2 – sed & Usage: จับคู่ทั้งบรรทัด
& แทนที่สิ่งที่จับคู่กับ REGEXP ที่กำหนด
$ sed 's@^.*$@<<<&>>>@g' path.txt <</usr/kbos/bin:/usr/local/bin:/usr/jbin/:/usr/bin:/usr/sas/bin>>> <</usr/local/sbin:/sbin:/bin/:/usr/sbin:/usr/bin:/opt/omni/bin:>>> <</opt/omni/lbin:/opt/omni/sbin:/root/bin>>>
ในตัวอย่างข้างต้น regexp มี "^.*$" ซึ่งจับคู่ทั้งบรรทัด ส่วน replacement <<<&>>> เขียนทั้งบรรทัดพร้อม <<< และ >>> ที่ต้นและท้ายบรรทัดตามลำดับ
III. การจัดกลุ่มและ Back-references ใน Sed
การจัดกลุ่มสามารถใช้ใน sed เหมือน regular expression ปกติ กลุ่มเปิดด้วย "\(" และปิดด้วย "\)" การจัดกลุ่มสามารถใช้ร่วมกับ back-referencing ได้
Back-reference คือการนำส่วนของ Regular Expression ที่เลือกโดยการจัดกลุ่มมาใช้ซ้ำ Back-references ใน sed สามารถใช้ได้ทั้งใน Regular Expression และในส่วน replacement ของคำสั่ง substitute
ตัวอย่างที่ 1: ได้เฉพาะ path แรกในแต่ละบรรทัด
$ sed 's/\(\/[^:]*\).*/\1/g' path.txt /usr/kbos/bin /usr/local/sbin /opt/omni/lbin
ในตัวอย่างข้างต้น \(\/[^:]*\) จับคู่ path ที่มีก่อน : แรก \1 แทนที่กลุ่มที่จับคู่ได้แรก
ตัวอย่างที่ 2: Multigrouping
ในไฟล์ path.txt เปลี่ยนลำดับฟิลด์ในบรรทัดสุดท้ายของไฟล์
$ sed '$s@\([^:]*\):\([^:]*\):\([^:]*\)@\3:\2:\1@g' path.txt /usr/kbos/bin:/usr/local/bin:/usr/jbin:/usr/bin:/usr/sas/bin /usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/omni/bin: /root/bin:/opt/omni/sbin:/opt/omni/lbin
ในคำสั่งข้างต้น $ ระบุให้แทนที่เกิดขึ้นเฉพาะบรรทัดสุดท้าย เอาต์พุตแสดงว่าลำดับค่า path ในบรรทัดสุดท้ายถูกกลับด้าน
ตัวอย่างที่ 3: ได้รายชื่อผู้ใช้ในไฟล์ /etc/passwd
ตัวอย่าง sed นี้แสดงเฉพาะฟิลด์แรกจากไฟล์ /etc/passwd
$sed 's/\([^:]*\).*/\1/' /etc/passwd root bin daemon adm lp sync shutdown
ตัวอย่างที่ 4: วงเล็บตัวอักษรแรกของแต่ละคำ
ตัวอย่าง sed นี้พิมพ์ตัวอักษรแรกของทุกคำในวงเล็บ
$ echo "Welcome To The Geek Stuff" | sed 's/\(\b[A-Z]\)/(\1)/g' (W)elcome (T)o (T)he (G)eek (S)tuff
ตัวอย่างที่ 5: ใส่คอมม่าในตัวเลขธรรมดา
มาสร้างไฟล์ชื่อ numbers ที่มีรายการตัวเลข คำสั่ง sed ด้านล่างใช้สำหรับใส่คอมม่าในตัวเลขจนถึงพัน
$ cat numbers
1234
12121
3434
123
$sed 's/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g' numbers
1,234
12,121
3,434
123