Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม Bash

การแทนที่ขั้นสูงของ Sed: เทคนิคและตัวอย่างปฏิบัติจริงสำหรับผู้เชี่ยวชาญ

การแทนที่ขั้นสูงของ Sed: เทคนิคและตัวอย่างปฏิบัติจริงสำหรับผู้เชี่ยวชาญบทความนี้เป็นส่วนหนึ่งของซีรีส์เคล็ดลับและเทคนิค 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