Unix / Linux - Biểu thức chính quy với SED

Trong chương này, chúng ta sẽ thảo luận chi tiết về các biểu thức chính quy với SED trong Unix.

Biểu thức chính quy là một chuỗi có thể được sử dụng để mô tả một số chuỗi ký tự. Biểu thức chính quy được sử dụng bởi một số lệnh Unix khác nhau, bao gồmed, sed, awk, grepvà ở một mức độ hạn chế hơn, vi.

Đây SED viết tắt của stream editor. Trình chỉnh sửa hướng luồng này được tạo riêng để thực thi các tập lệnh. Do đó, tất cả dữ liệu đầu vào bạn cấp vào nó sẽ đi qua và chuyển đến STDOUT và nó không thay đổi tệp đầu vào.

Mời sed

Trước khi bắt đầu, hãy đảm bảo rằng chúng tôi có một bản sao cục bộ của /etc/passwd tập tin văn bản để làm việc với sed.

Như đã đề cập trước đây, sed có thể được gọi bằng cách gửi dữ liệu qua một đường ống đến nó như sau:

$ cat /etc/passwd | sed
Usage: sed [OPTION]... {script-other-script} [input-file]...

  -n, --quiet, --silent
                 suppress automatic printing of pattern space
  -e script, --expression = script
...............................

Các cat lệnh kết xuất nội dung của /etc/passwd đến sedthông qua đường ống vào không gian mẫu của sed. Không gian mẫu là vùng đệm công việc bên trong mà sed sử dụng cho các hoạt động của nó.

Cú pháp chung sed

Sau đây là cú pháp chung cho sed -

/pattern/action

Đây, pattern là một biểu thức chính quy và actionlà một trong các lệnh được đưa ra trong bảng sau. Nếupattern bị bỏ qua, action được thực hiện cho mọi dòng như chúng ta đã thấy ở trên.

Ký tự gạch chéo (/) bao quanh mẫu là bắt buộc vì chúng được sử dụng làm dấu phân cách.

Sr.No. Phạm vi & Mô tả
1

p

In dòng

2

d

Xóa dòng

3

s/pattern1/pattern2/

Thay thế lần xuất hiện đầu tiên của mẫu1 bằng mẫu2

Xóa tất cả các dòng với sed

Bây giờ chúng ta sẽ hiểu cách xóa tất cả các dòng bằng sed. Gọi lại sed; nhưng chiếc sedan bây giờ được cho là sử dụngediting command delete line, được biểu thị bằng một chữ cái d -

$ cat /etc/passwd | sed 'd'
$

Thay vì gọi sed bằng cách gửi một tệp đến nó thông qua một đường ống, sed có thể được hướng dẫn để đọc dữ liệu từ một tệp, như trong ví dụ sau.

Lệnh sau thực hiện hoàn toàn giống như trong ví dụ trước, không có lệnh cat -

$ sed -e 'd' /etc/passwd
$

Địa chỉ sed

Sed cũng hỗ trợ địa chỉ. Địa chỉ là các vị trí cụ thể trong một tệp hoặc một phạm vi nơi một lệnh chỉnh sửa cụ thể sẽ được áp dụng. Khi sed gặp không có địa chỉ, nó thực hiện các hoạt động của nó trên mọi dòng trong tệp.

Lệnh sau thêm một địa chỉ cơ bản vào lệnh sed mà bạn đang sử dụng:

$ cat /etc/passwd | sed '1d' |more
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
$

Lưu ý rằng số 1 được thêm vào trước delete editchỉ huy. Thao tác này hướng dẫn sed thực hiện lệnh chỉnh sửa trên dòng đầu tiên của tệp. Trong ví dụ này, sed sẽ xóa dòng đầu tiên của/etc/password và in phần còn lại của tệp.

Dãy địa chỉ sed

Bây giờ chúng ta sẽ hiểu cách làm việc với the sed address ranges. Vì vậy, điều gì xảy ra nếu bạn muốn xóa nhiều hơn một dòng khỏi một tệp? Bạn có thể chỉ định một dải địa chỉ với sed như sau:

$ cat /etc/passwd | sed '1, 5d' |more
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
$

Lệnh trên sẽ được áp dụng trên tất cả các dòng bắt đầu từ 1 đến 5. Thao tác này sẽ xóa năm dòng đầu tiên.

Hãy thử các dải địa chỉ sau:

Sr.No. Phạm vi & Mô tả
1

'4,10d'

Dòng bắt đầu từ 4 tháng đến 10 tháng được xóa

2

'10,4d'

Chỉ có dòng thứ 10 bị xóa, vì sed không hoạt động theo hướng ngược lại

3

'4,+5d'

Điều này khớp với dòng 4 trong tệp, xóa dòng đó, tiếp tục xóa năm dòng tiếp theo, sau đó ngừng xóa và in phần còn lại

4

'2,5!d'

Thao tác này sẽ xóa mọi thứ ngoại trừ bắt đầu từ dòng thứ 2 đến dòng thứ 5

5

'1~3d'

Thao tác này sẽ xóa dòng đầu tiên, bước qua ba dòng tiếp theo và sau đó xóa dòng thứ tư. Sed tiếp tục áp dụng mẫu này cho đến cuối tệp.

6

'2~2d'

Điều này cho sed xóa dòng thứ hai, bước qua dòng tiếp theo, xóa dòng tiếp theo và lặp lại cho đến khi đạt đến cuối tệp

7

'4,10p'

Dòng bắt đầu từ 4 tháng đến 10 tháng được in

số 8

'4,d'

Điều này tạo ra lỗi cú pháp

9

',10d'

Điều này cũng sẽ tạo ra lỗi cú pháp

Note - Trong khi sử dụng p hành động, bạn nên sử dụng -ntùy chọn để tránh lặp lại việc in dòng. Kiểm tra sự khác biệt giữa hai lệnh sau:

$ cat /etc/passwd | sed -n '1,3p'
Check the above command without -n as follows −
$ cat /etc/passwd | sed '1,3p'

Lệnh thay thế

Lệnh thay thế, ký hiệu là s, sẽ thay thế bất kỳ chuỗi nào bạn chỉ định bằng bất kỳ chuỗi nào khác mà bạn chỉ định.

Để thay thế một chuỗi này bằng một chuỗi khác, sed cần có thông tin về nơi chuỗi đầu tiên kết thúc và chuỗi thay thế bắt đầu. Đối với điều này, chúng tôi tiến hành liên kết hai chuỗi bằng dấu gạch chéo (/) tính cách.

Lệnh sau thay thế lần xuất hiện đầu tiên trên một dòng của chuỗi root với chuỗi amrood.

$ cat /etc/passwd | sed 's/root/amrood/'
amrood:x:0:0:root user:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
..........................

Điều rất quan trọng cần lưu ý là sed chỉ thay thế lần xuất hiện đầu tiên trên một dòng. Nếu gốc chuỗi xuất hiện nhiều hơn một lần trên một dòng thì chỉ so khớp đầu tiên sẽ được thay thế.

Để sed thực hiện thay thế toàn cục, hãy thêm ký tự g đến cuối lệnh như sau:

$ cat /etc/passwd | sed 's/root/amrood/g'
amrood:x:0:0:amrood user:/amrood:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
...........................

Cờ thay thế

Có một số cờ hữu ích khác có thể được chuyển ngoài g cờ và bạn có thể chỉ định nhiều hơn một cờ cùng một lúc.

Sr.No. Cờ & Mô tả
1

g

Thay thế tất cả các trận đấu, không chỉ trận đấu đầu tiên

2

NUMBER

Chỉ thay thế trận đấu thứ NUMBER

3

p

Nếu thay thế được thực hiện, sau đó in không gian mẫu

4

w FILENAME

Nếu thay thế được thực hiện, sau đó ghi kết quả vào FILENAME

5

I or i

Đối sánh theo cách không phân biệt chữ hoa chữ thường

6

M or m

Ngoài hành vi bình thường của các ký tự biểu thức chính quy đặc biệt ^ và $, cờ này khiến ^ khớp với chuỗi trống sau dòng mới và $ khớp với chuỗi trống trước dòng mới

Sử dụng dấu phân tách chuỗi thay thế

Giả sử bạn phải thực hiện thay thế trên một chuỗi bao gồm ký tự gạch chéo về phía trước. Trong trường hợp này, bạn có thể chỉ định một dấu phân tách khác bằng cách cung cấp ký tự được chỉ định saus.

$ cat /etc/passwd | sed 's:/root:/amrood:g'
amrood:x:0:0:amrood user:/amrood:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh

Trong ví dụ trên, chúng tôi đã sử dụng : như là delimiter thay vì gạch chéo / vì chúng tôi đang cố gắng tìm kiếm /root thay vì gốc đơn giản.

Thay thế bằng Không gian trống

Sử dụng một chuỗi thay thế trống để xóa chuỗi gốc khỏi /etc/passwd hoàn toàn tập tin -

$ cat /etc/passwd | sed 's/root//g'
:x:0:0::/:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh

Thay thế địa chỉ

Nếu bạn muốn thay thế chuỗi sh với chuỗi quiet chỉ trên dòng 10, bạn có thể chỉ định nó như sau:

$ cat /etc/passwd | sed '10s/sh/quiet/g'
root:x:0:0:root user:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/quiet

Tương tự, để thay thế dải địa chỉ, bạn có thể làm như sau:

$ cat /etc/passwd | sed '1,5s/sh/quiet/g'
root:x:0:0:root user:/root:/bin/quiet
daemon:x:1:1:daemon:/usr/sbin:/bin/quiet
bin:x:2:2:bin:/bin:/bin/quiet
sys:x:3:3:sys:/dev:/bin/quiet
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh

Như bạn có thể thấy từ đầu ra, năm dòng đầu tiên có chuỗi sh thay đổi để quiet, nhưng những dòng còn lại vẫn được giữ nguyên.

Lệnh phù hợp

Bạn sẽ sử dụng p tùy chọn cùng với -n tùy chọn để in tất cả các dòng phù hợp như sau:

$ cat testing | sed -n '/root/p'
root:x:0:0:root user:/root:/bin/sh
[root@ip-72-167-112-17 amrood]# vi testing
root:x:0:0:root user:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh

Sử dụng Cụm từ Thông dụng

Trong khi đối sánh các mẫu, bạn có thể sử dụng biểu thức chính quy để linh hoạt hơn.

Kiểm tra ví dụ sau phù hợp với tất cả các dòng bắt đầu bằng daemon và sau đó xóa chúng -

$ cat testing | sed '/^daemon/d'
root:x:0:0:root user:/root:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh

Sau đây là ví dụ xóa tất cả các dòng kết thúc bằng sh -

$ cat testing | sed '/sh$/d'
sync:x:4:65534:sync:/bin:/bin/sync

Bảng sau liệt kê bốn ký tự đặc biệt rất hữu ích trong biểu thức chính quy.

Sr.No. Nhân vật & Mô tả
1

^

Khớp với đầu dòng

2

$

Khớp với cuối dòng

3

.

Khớp với bất kỳ ký tự đơn nào

4

*

Khớp với không hoặc nhiều lần xuất hiện của ký tự trước đó

5

[chars]

So khớp bất kỳ một trong các ký tự được cho trong ký tự, trong đó ký tự là một chuỗi ký tự. Bạn có thể sử dụng ký tự - để chỉ ra một loạt các ký tự.

Nhân vật phù hợp

Xem thêm một vài biểu thức để chứng minh việc sử dụng metacharacters. Ví dụ, mẫu sau:

Sr.No. Biểu thức & Mô tả
1

/a.c/

Đối sánh các dòng có chứa các chuỗi chẳng hạn như a+c, a-c, abc, matcha3c

2

/a*c/

Khớp các chuỗi giống nhau với các chuỗi chẳng hạn như ace, yaccarctic

3

/[tT]he/

Khớp với chuỗi Thethe

4

/^$/

Khớp các dòng trống

5

/^.*$/

Khớp toàn bộ dòng bất kể nó là gì

6

/ */

Khớp một hoặc nhiều khoảng trắng

7

/^$/

Diêm blank dòng

Bảng sau đây cho thấy một số bộ ký tự được sử dụng thường xuyên:

Sr.No. Đặt & Mô tả
1

[a-z]

Khớp một chữ cái thường

2

[A-Z]

Khớp một chữ hoa đơn lẻ

3

[a-zA-Z]

Khớp một chữ cái

4

[0-9]

Khớp một số

5

[a-zA-Z0-9]

Khớp một chữ cái hoặc một số

Từ khóa lớp nhân vật

Một số từ khóa đặc biệt thường có sẵn cho regexps, đặc biệt là các tiện ích GNU sử dụng regexps. Chúng rất hữu ích cho các biểu thức chính quy sed vì chúng đơn giản hóa mọi thứ và nâng cao khả năng đọc.

Ví dụ, các ký tự a through z và các nhân vật A through Z, tạo thành một lớp ký tự như vậy có từ khóa [[:alpha:]]

Sử dụng từ khóa lớp ký tự bảng chữ cái, lệnh này chỉ in những dòng đó trong /etc/syslog.conf tệp bắt đầu bằng một chữ cái trong bảng chữ cái -

$ cat /etc/syslog.conf | sed -n '/^[[:alpha:]]/p'
authpriv.*                         /var/log/secure
mail.*                             -/var/log/maillog
cron.*                             /var/log/cron
uucp,news.crit                     /var/log/spooler
local7.*                           /var/log/boot.log

Bảng sau đây là danh sách đầy đủ các từ khóa lớp ký tự có sẵn trong GNU sed.

Sr.No. Lớp nhân vật & Mô tả
1

[[:alnum:]]

Chữ và số [az AZ 0-9]

2

[[:alpha:]]

Bảng chữ cái [az AZ]

3

[[:blank:]]

Ký tự trống (dấu cách hoặc tab)

4

[[:cntrl:]]

Kiểm soát ký tự

5

[[:digit:]]

Các số [0-9]

6

[[:graph:]]

Bất kỳ ký tự hiển thị nào (không bao gồm khoảng trắng)

7

[[:lower:]]

Chữ thường [az]

số 8

[[:print:]]

Các ký tự có thể in được (ký tự không điều khiển)

9

[[:punct:]]

Các ký tự dấu câu

10

[[:space:]]

Khoảng trắng

11

[[:upper:]]

Chữ hoa [AZ]

12

[[:xdigit:]]

Chữ số thập lục phân [0-9 af AF]

Aampersand References

Các sed metacharacter &đại diện cho nội dung của mẫu đã được khớp. Ví dụ: giả sử bạn có một tệp có tênphone.txt đầy đủ các số điện thoại, chẳng hạn như sau:

5555551212
5555551213
5555551214
6665551215
6665551216
7775551217

Bạn muốn làm area code(ba chữ số đầu tiên) được bao quanh bởi dấu ngoặc đơn để dễ đọc hơn. Để thực hiện việc này, bạn có thể sử dụng ký tự thay thế và dấu -

$ sed -e 's/^[[:digit:]][[:digit:]][[:digit:]]/(&)/g' phone.txt
(555)5551212
(555)5551213
(555)5551214
(666)5551215

(666)5551216
(777)5551217

Ở đây trong phần mẫu, bạn đang khớp 3 chữ số đầu tiên và sau đó sử dụng & bạn đang thay thế 3 chữ số đó với xung quanh parentheses.

Sử dụng nhiều lệnh sed

Bạn có thể sử dụng nhiều lệnh sed trong một lệnh sed như sau:

$ sed -e 'command1' -e 'command2' ... -e 'commandN' files

Đây command1 xuyên qua commandNlà các lệnh sed thuộc loại đã được thảo luận trước đây. Các lệnh này được áp dụng cho từng dòng trong danh sách các tệp do tệp đưa ra.

Sử dụng cơ chế tương tự, chúng ta có thể viết ví dụ số điện thoại ở trên như sau:

$ sed -e 's/^[[:digit:]]\{3\}/(&)/g'  \ 
   -e 's/)[[:digit:]]\{3\}/&-/g' phone.txt 
(555)555-1212 
(555)555-1213 
(555)555-1214 
(666)555-1215 
(666)555-1216 
(777)555-1217

Note - Trong ví dụ trên, thay vì lặp lại từ khóa lớp ký tự [[:digit:]] ba lần, chúng tôi đã thay thế nó bằng \{3\}, có nghĩa là biểu thức chính quy trước được so khớp ba lần. Chúng tôi cũng đã sử dụng\ để đưa ra ngắt dòng và điều này phải được loại bỏ trước khi lệnh được chạy.

Tham khảo trở lại

Các ampersand metacharacterrất hữu ích, nhưng hữu ích hơn nữa là khả năng xác định các vùng cụ thể trong biểu thức chính quy. Những vùng đặc biệt này có thể được sử dụng làm tham chiếu trong chuỗi thay thế của bạn. Bằng cách xác định các phần cụ thể của một biểu thức chính quy, sau đó bạn có thể tham chiếu lại các phần đó bằng một ký tự tham chiếu đặc biệt.

Làm back references, trước tiên bạn phải xác định một vùng và sau đó tham chiếu lại vùng đó. Để xác định một khu vực, bạn chènbackslashed parenthesesxung quanh mỗi khu vực quan tâm. Vùng đầu tiên mà bạn bao quanh bằng dấu gạch chéo ngược sau đó được tham chiếu bởi\1, khu vực thứ hai bởi \2, và như thế.

Giả định phone.txt có văn bản sau -

(555)555-1212
(555)555-1213
(555)555-1214
(666)555-1215
(666)555-1216
(777)555-1217

Hãy thử lệnh sau:

$ cat phone.txt | sed 's/\(.*)\)\(.*-\)\(.*$\)/Area \ 
   code: \1 Second: \2 Third: \3/' 
Area code: (555) Second: 555- Third: 1212 
Area code: (555) Second: 555- Third: 1213 
Area code: (555) Second: 555- Third: 1214 
Area code: (666) Second: 555- Third: 1215 
Area code: (666) Second: 555- Third: 1216 
Area code: (777) Second: 555- Third: 1217

Note - Trong ví dụ trên, mỗi biểu thức chính quy bên trong dấu ngoặc đơn sẽ được tham chiếu lại bởi \1, \2và như thế. Chúng tôi vừa dùng\để ngắt dòng ở đây. Điều này nên được loại bỏ trước khi chạy lệnh.