103.7 Bài 2
Chứng chỉ: |
LPIC-1 |
---|---|
Phiên bản: |
5.0 |
Chủ đề: |
103 Lệnh GNU và Unix |
Mục tiêu: |
103.7 Tìm kiếm Tệp Văn bản bằng Biểu thức Chính quy |
Bài: |
2 trên 2 |
Giới thiệu
Việc truyền dữ liệu qua một chuỗi các lệnh được dẫn ống cho phép chúng ta áp dụng các bộ lọc phức hợp dựa trên các biểu thức chính quy. Biểu thức chính quy là một kỹ thuật quan trọng không chỉ được sử dụng trong quản trị hệ thống mà còn trong cả việc khai phá dữ liệu và các lĩnh vực liên quan. Hai lệnh đặc biệt phù hợp để thao tác với tệp và dữ liệu văn bản bằng biểu thức chính quy là grep
và sed
. grep
là công cụ tìm mẫu và sed
là trình chỉnh sửa luồng. Bản thân chúng đã rất hữu ích, nhưng chúng thậm chí sẽ còn nổi bật hơn khi được sử dụng cùng với các tiến trình khác.
Công cụ tìm Mẫu: grep
Một trong những cách sử dụng phổ biến nhất của grep
là tạo điều kiện cho việc kiểm tra các tệp dài sử dụng biểu thức chính quy làm bộ lọc được áp dụng cho mỗi dòng. Nó có thể được sử dụng để chỉ hiển thị các dòng bắt đầu bằng một thuật ngữ nhất định. Ví dụ: grep
có thể được sử dụng để kiểm tra một tệp cấu hình cho các mô-đun nhân và chỉ liệt kê các dòng tùy chọn:
$ grep '^options' /etc/modprobe.d/alsa-base.conf options snd-pcsp index=-2 options snd-usb-audio index=-2 options bt87x index=-2 options cx88_alsa index=-2 options snd-atiixp-modem index=-2 options snd-intel8x0m index=-2 options snd-via82xx-modem index=-2
Ký tự ống |
có thể được sử dụng để chuyển hướng trực tiếp đầu ra của lệnh sang đầu vào của grep
. Ví dụ sau sử dụng biểu thức ngoặc vuông để chọn các dòng từ đầu ra fdisk -l
bắt đầu bằng Disk /dev/sda
hoặc Disk /dev/sdb
:
# fdisk -l | grep '^Disk /dev/sd[ab]' Disk /dev/sda: 320.1 GB, 320072933376 bytes, 625142448 sectors Disk /dev/sdb: 7998 MB, 7998537728 bytes, 15622144 sectors
Việc chỉ lựa chọn các dòng có kết quả trùng khớp có thể sẽ không phù hợp với một số tác vụ cụ thể đòi hỏi phải điều chỉnh hành vi của grep
thông qua các tùy chọn của nó. Ví dụ: tùy chọn -c
hoặc --count
sẽ cho grep
biết có bao nhiêu dòng phù hợp:
# fdisk -l | grep '^Disk /dev/sd[ab]' -c 2
Tùy chọn có thể được đặt trước hoặc sau biểu thức chính quy. Các tùy chọn grep
quan trọng khác là:
-c
hoặc--count
-
Thay vì hiển thị kết quả tìm kiếm, nó sẽ chỉ hiển thị tổng số lần trùng khớp xảy ra trong bất kỳ tệp cụ thể nào.
-i
hoặc--ignore-case
-
Khiến cho phiên tìm kiếm không phân biệt chữ hoa chữ thường.
-f FILE
hoặc--file=FILE
-
Cho biết tệp chứa biểu thức chính quy sẽ sử dụng.
-n
hoặc--line-number
-
Hiển thị số dòng.
-v
hoặc--invert-match
-
Chọn mọi dòng ngoại trừ những dòng có chứa kết quả trùng khớp.
-H
hoặc--with-filename
-
In cả tên của tệp có chứa dòng.
-z
hoặc--null-data
-
Thay vì để
grep
xử lý các luồng dữ liệu đầu vào và đầu ra dưới dạng các dòng riêng biệt (sử dụng ký tự xuống dòng theo mặc định), lệnh sẽ lấy đầu vào hoặc đầu ra dưới dạng một chuỗi các dòng. Khi kết hợp đầu ra từ lệnhfind
bằng tùy chọn-print0
với lệnhgrep
, tùy chọn-z
hoặc--null-data
nên được sử dụng để xử lý luồng theo cách tương tự.
Mặc dù được kích hoạt mặc định khi nhiều đường dẫn tệp được cung cấp làm đầu vào, tùy chọn -H
sẽ không được kích hoạt cho các tệp đơn lẻ. Điều đó có thể sẽ rất quan trọng trong các tình huống đặc biệt, chẳng hạn như khi grep
được gọi trực tiếp bởi find
:
$ find /usr/share/doc -type f -exec grep -i '3d modeling' "{}" \; | cut -c -100 artistic aspects of 3D modeling. Thus this might be the application you are This major approach of 3D modeling has not been supported oce is a C++ 3D modeling library. It can be used to develop CAD/CAM softwares, for instance [FreeCad
Trong ví dụ này, find
sẽ liệt kê mọi tệp trong /usr/share/doc
, sau đó chuyển từng tệp tới grep
, từ đó thực hiện tìm kiếm 3d moedeling
không phân biệt chữ hoa chữ thường bên trong tệp. Đường ống dẫn tới cut
ở đó chỉ để giới hạn độ dài đầu ra ở 100 cột. Tuy nhiên, hãy lưu ý rằng không có cách nào để biết các dòng này đến từ tệp nào. Vấn đề này sẽ được giải quyết bằng cách thêm -H
vào grep
:
$ find /usr/share/doc -type f -exec grep -i -H '3d modeling' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support
Giờ đây, ta có thể xác định các tệp nơi mà mỗi kết quả trùng khớp được tìm thấy. Để làm cho danh sách trở nên đầy đủ hơn, các dòng đầu và cuối có thể được thêm vào các dòng có kết quả trùng khớp:
$ find /usr/share/doc -type f -exec grep -i -H -1 '3d modeling' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md-application Blender), OpenSCAD focuses on the CAD aspects rather t /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/openscad/README.md-looking for when you are planning to create 3D models of machine p /usr/share/doc/opencsg/doc/publications.html-3D graphics library for Constructive Solid Geometry (CS /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support /usr/share/doc/opencsg/doc/publications.html-by real-time computer graphics until recently.
Tùy chọn -1
sẽ hướng dẫn grep
bao gồm thêm một dòng trước và sau khi nó tìm thấy một dòng có kết quả trùng khớp. Những dòng bổ sung này được gọi là dòng ngữ cảnh và được xác định trong đầu ra bằng dấu trừ sau tên tệp. Ta có thể thu được kết quả tương tự với -C 1
hoặc --context=1
và các số lượng dòng ngữ cảnh khác có thể được chỉ định.
Có hai chương trình bổ trợ cho grep là egrep
và fgrep
. Chương trình egrep
tương đương với lệnh grep -E
có kết hợp các tính năng bổ sung ngoài các biểu thức chính quy cơ bản. Ví dụ: với egrep
, ta có thể sử dụng các tính năng biểu thức chính quy mở rộng như phân nhánh:
$ find /usr/share/doc -type f -exec egrep -i -H -1 '3d (modeling|printing)' "{}" \; | cut -c -100 /usr/share/doc/openscad/README.md-application Blender), OpenSCAD focuses on the CAD aspects rather t /usr/share/doc/openscad/README.md:artistic aspects of 3D modeling. Thus this might be the applicatio /usr/share/doc/openscad/README.md-looking for when you are planning to create 3D models of machine p /usr/share/doc/openscad/RELEASE_NOTES.md-* Support for using 3D-Mouse / Joystick / Gamepad input dev /usr/share/doc/openscad/RELEASE_NOTES.md:* 3D Printing support: Purchase from a print service partne /usr/share/doc/openscad/RELEASE_NOTES.md-* New export file formats: SVG, 3MF, AMF /usr/share/doc/opencsg/doc/publications.html-3D graphics library for Constructive Solid Geometry (CS /usr/share/doc/opencsg/doc/publications.html:This major approach of 3D modeling has not been support /usr/share/doc/opencsg/doc/publications.html-by real-time computer graphics until recently.
Trong ví dụ này, 3D modeling
hoặc 3D printing
sẽ khớp với biểu thức và không phân biệt chữ hoa chữ thường. Để chỉ hiển thị các phần của luồng văn bản khớp với biểu thức được sử dụng bởi egrep
, hãy sử dụng tùy chọn -o
.
Chương trình fgrep
cũng tương đương với grep -F
, tức là nó không phân tích cú pháp các biểu thức chính quy. Nó rất hữu ích trong các phiên tìm kiếm đơn giản mà mục tiêu là khớp với một biểu thức bằng chữ. Do đó, các ký tự đặc biệt như ký hiệu đô la và dấu chấm sẽ được hiểu theo nghĩa đen chứ không theo nghĩa của chúng trong biểu thức chính quy.
Trình chỉnh sửa Luồng: sed
Mục đích của chương trình sed
là sửa đổi dữ liệu dựa trên văn bản theo một cách không tương tác. Có nghĩa là tất cả các thao tác chỉnh sửa đều sẽ được thực hiện theo hướng dẫn định sẵn chứ không phải tùy tiện gõ trực tiếp vào văn bản hiển thị trên màn hình. Theo thuật ngữ hiện đại, sed
có thể được hiểu là trình phân tích cú pháp mẫu: cho một văn bản làm đầu vào, nó sẽ đặt nội dung tùy chỉnh tại các vị trí được xác định trước hoặc khi nó tìm thấy kết quả trùng khớp cho một biểu thức chính quy.
Sed, như tên của nó, rất phù hợp với văn bản được truyền qua các đường ống. Cú pháp cơ bản của nó là sed -f SCRIPT
khi các hướng dẫn chỉnh sửa được lưu trữ trong tệp SCRIPT
hoặc sed -e COMMANDS
để thực thi COMMANDS
trực tiếp từ dòng lệnh. Nếu không có -f
hoặc -e
, sed
sẽ sử dụng tham số không phải tùy chọn đầu tiên làm tệp tệp lệnh. Ta cũng có thể sử dụng tệp làm đầu vào bằng cách cung cấp đường dẫn của nó làm đối số cho sed
.
Các lệnh sed
sẽ bao gồm một ký tự đơn, có thể đứng trước một địa chỉ hoặc theo sau một hoặc nhiều tùy chọn và sẽ được áp dụng mỗi lần cho một dòng. Địa chỉ có thể là một số dòng đơn, một biểu thức chính quy hoặc một phạm vi các dòng. Ví dụ: dòng đầu tiên của luồng văn bản có thể bị xóa bằng 1d
, trong đó, 1
chỉ định dòng mà lệnh xóa d
sẽ được áp dụng. Để làm rõ cách sử dụng của sed
, hãy lấy đầu ra của lệnh factor `seq 12`
trả về các thừa số nguyên tố cho các số từ 1 đến 12:
$ factor `seq 12` 1: 2: 2 3: 3 4: 2 2 5: 5 6: 2 3 7: 7 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
Việc xóa dòng đầu tiên bằng sed
có thể được thực hiện bằng 1d
:
$ factor `seq 12` | sed 1d 2: 2 3: 3 4: 2 2 5: 5 6: 2 3 7: 7 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
Ta có thể chỉ định một loạt các dòng được ngăn cách bằng dấu phẩy:
$ factor `seq 12` | sed 1,7d 8: 2 2 2 9: 3 3 10: 2 5 11: 11 12: 2 2 3
Chúng ta có thể sử dụng nhiều hơn một lệnh được phân tách bằng dấu chấm phẩy trong cùng một lần thực thi. Tuy nhiên, trong trường hợp này, chúng ta phải đặt chúng trong dấu ngoặc đơn để vỏ không diễn giải dấu chấm phẩy:
$ factor `seq 12` | sed "1,7d;11d" 8: 2 2 2 9: 3 3 10: 2 5 12: 2 2 3
Trong ví dụ này, hai lệnh xóa đã được thực hiện, đầu tiên là trên các dòng từ 1 đến 7 và sau đó trên dòng 11. Một địa chỉ cũng có thể là một biểu thức chính quy; vì vậy, chỉ những dòng khớp mới bị ảnh hưởng bởi lệnh:
$ factor `seq 12` | sed "1d;/:.*2.*/d" 3: 3 5: 5 7: 7 9: 3 3 11: 11
Biểu thức chính quy :.*2.*
sẽ khớp với bất kỳ lần xuất hiện nào của số 2 ở bất kỳ đâu sau dấu hai chấm và từ đó xóa đi các dòng tương ứng có chứa thừa số 2. Với sed
, bất kỳ thứ gì được đặt giữa các dấu gạch chéo (/
) đều được coi là biểu thức chính quy và theo mặc định, tất cả các RE cơ bản đều sẽ được hỗ trợ. Ví dụ: sed -e "/^#/d" /etc/services
sẽ hiển thị nội dung của tệp /etc/services
mà không có dòng bắt đầu bằng #
(dòng chú thích).
Lệnh xóa d
chỉ là một trong nhiều lệnh chỉnh sửa do sed
cung cấp. Thay vì xóa một dòng, sed
có thể thay thế nó bằng một đoạn văn bản nhất định:
$ factor `seq 12` | sed "1d;/:.*2.*/c REMOVED" REMOVED 3: 3 REMOVED 5: 5 REMOVED 7: 7 REMOVED 9: 3 3 REMOVED 11: 11 REMOVED
Hướng dẫn c REMOVED
sẽ chỉ đơn giản là thay thế một dòng bằng REMOVED
. Trong trường hợp của ví dụ, mọi dòng có chuỗi con khớp với biểu thức chính quy :.*2.*
đều sẽ bị ảnh hưởng bởi lệnh c REMOVED
. Lệnh a TEXT
sẽ sao chép văn bản được chỉ định bởi TEXT
sang một dòng mới ở sau dòng có kết quả trùng khớp. Lệnh r FILE
cũng sẽ thực hiện tương tự nhưng sẽ sao chép nội dung của tệp được chỉ định bởi FILE
. Lệnh w
sẽ thực hiện ngược lại lệnh r
, tức là dòng sẽ được thêm vào tệp được chỉ định.
Cho đến nay, lệnh sed
được sử dụng nhiều nhất là s/FIND/REPLACE/
. Lệnh này được sử dụng để thay thế kết quả trùng khớp với biểu thức chính quy FIND
bằng văn bản được biểu thị bằng REPLACE
. Ví dụ: lệnh s/hda/sda/
sẽ thay thế một chuỗi con khớp với RE hda
bằng sda
. Chỉ kết quả trùng khớp đầu tiên được tìm thấy trong dòng sẽ được thay thế trừ khi cờ g
được đặt sau lệnh như trong s/hda/sda/g
.
Một ví dụ điển hình thực tế hơn sẽ giúp minh họa các tính năng của sed
. Giả sử một phòng khám y tế muốn gửi tin nhắn văn bản cho khách hàng của mình để nhắc nhở họ về lịch hẹn cho ngày hôm sau. Đây là một kịch bản triển khai điển hình dựa trên dịch vụ tin nhắn tức thời chuyên nghiệp. Dịch vụ này sẽ cung cấp API để truy cập vào hệ thống chịu trách nhiệm gửi tin nhắn. Những tin nhắn này thường bắt nguồn từ cùng một hệ thống chạy ứng dụng kiểm soát các cuộc hẹn với khách hàng và được kích hoạt bởi một thời điểm cụ thể trong ngày hoặc một số sự kiện khác. Trong tình huống giả định này, ứng dụng có thể tạo một tệp có tên appointments.csv
chứa dữ liệu dạng bảng với tất cả các cuộc hẹn cho ngày hôm sau, sau đó được sed
sử dụng để hiển thị tin nhắn văn bản từ tệp mẫu có tên template.txt
. Các tệp CSV là một cách tiêu chuẩn để xuất dữ liệu từ các truy vấn cơ sở dữ liệu. Do đó, các cuộc hẹn mẫu có thể được đưa ra dưới dạng như sau:
$ cat appointments.csv "NAME","TIME","PHONE" "Carol","11am","55557777" "Dave","2pm","33334444"
Dòng đầu tiên chứa các nhãn cho mỗi cột và sẽ được sử dụng để khớp với các thẻ bên trong tệp mẫu:
$ cat template.txt Hey <NAME>, don't forget your appointment tomorrow at <TIME>.
Các dấu nhỏ hơn <
và lớn hơn >
được đặt xung quanh nhãn chỉ để giúp xác định chúng là thẻ. Tệp lệnh Bash sau đây phân tích cú pháp tất cả các cuộc hẹn được xếp hàng đợi bằng cách sử dụng template.txt
làm mẫu tin nhắn:
#! /bin/bash TEMPLATE=`cat template.txt` TAGS=(`sed -ne '1s/^"//;1s/","/\n/g;1s/"$//p' appointments.csv`) mapfile -t -s 1 ROWS < appointments.csv for (( r = 0; r < ${#ROWS[*]}; r++ )) do MSG=$TEMPLATE VALS=(`sed -e 's/^"//;s/","/\n/g;s/"$//' <<<${ROWS[$r]}`) for (( c = 0; c < ${#TAGS[*]}; c++ )) do MSG=`sed -e "s/<${TAGS[$c]}>/${VALS[$c]}/g" <<<"$MSG"` done echo curl --data message=\"$MSG\" --data phone=\"${VALS[2]}\" https://mysmsprovider/api done
Một tệp lệnh sản xuất thực tế cũng sẽ xử lý tác vụ xác thực, kiểm tra lỗi và ghi nhật ký, nhưng ví dụ của chúng ta từ đầu đã có các chức năng cơ bản. Các lệnh đầu tiên được thực thi bởi sed
chỉ được áp dụng cho dòng đầu tiên — địa chỉ 1
trong 1s/^"//;1s/","/\n/g;1s/"$//p
— nhằm xóa các dấu trích dẫn kép ở đầu và cuối — 1s/^"//
và 1s/"$//
— và để thay thế các dấu phân tách trường bằng một ký tự xuống dòng (1s/","/\n/ g
). Chỉ có dòng đầu tiên là cần để tải tên cột; vì vậy, các dòng không khớp sẽ được nén bởi tùy chọn -n
và yêu cầu ta đặt cờ p
sau lệnh sed
cuối cùng để in dòng khớp. Các thẻ sau đó sẽ được lưu trữ trong biến TAGS
dưới dạng một mảng Bash. Một biến mảng Bash khác sẽ được tạo bởi lệnh mapfile
để lưu các dòng chứa các cuộc hẹn trong biến mảng ROWS
.
Vòng lặp for
được sử dụng để xử lý từng dòng lịch hẹn được tìm thấy trong ROWS
. Sau đó, dấu trích dẫn kép và dấu phân cách trong cuộc hẹn — cuộc hẹn nằm trong biến ${ROWS[$r]}
được sử dụng làm here string — sẽ được thay thế bằng sed
tương tự như các lệnh được sử dụng để tải thẻ. Các giá trị riêng biệt cho cuộc hẹn sau đó sẽ được lưu trữ trong biến mảng VALS
mà trong đó, các chỉ số con của mảng 0, 1 và 2 tương ứng với các giá trị cho NAME
, TIME
và PHONE
.
Cuối cùng, một vòng lặp for
lồng nhau sẽ đi qua mảng TAGS
và thay thế từng thẻ được tìm thấy trong mẫu bằng giá trị tương ứng của nó trong VALS
. Biến MSG
sẽ giữ một bản sao của mẫu được hiển thị và được cập nhật bởi trình thay thế lệnh s/<${TAGS[$c]}>/${VALS[$c]}/g
trên mỗi vòng lặp đi qua TAGS
.
Điều này dẫn đến một thông báo được hiển thị như sau: "Hey Carol, don’t forget your appointment tomorrow at 11am."
Sau đó, thông báo được hiển thị có thể được gửi dưới dạng tham số thông qua yêu cầu HTTP với curl
dưới dạng thư hoặc bất kỳ phương pháp tương tự nào khác.
Kết hợp grep và sed
Các lệnh grep
và sed
có thể được sử dụng cùng nhau khi chúng ta cần các thủ tục khai phá văn bản phức tạp hơn. Ví dụ, với tư cách là quản trị viên hệ thống, chúng ta có thể sẽ phải kiểm tra tất cả các lần đăng nhập vào máy chủ. Tệp /var/log/wtmp
ghi lại tất cả các lần đăng nhập và đăng xuất, trong khi tệp /var/log/btmp
ghi lại các lần đăng nhập không thành công. Chúng được viết ở định dạng nhị phân và có thể được đọc bằng lệnh last
và lastb
tương ứng.
Đầu ra của lastb
không chỉ hiển thị tên người dùng được sử dụng trong lần đăng nhập không hợp lệ mà còn cả địa chỉ IP của người dùng đó:
# lastb -d -a -n 10 --time-format notime user ssh:notty (00:00) 81.161.63.251 nrostagn ssh:notty (00:00) vmd60532.contaboserver.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 46.6.11.56 pi ssh:notty (00:00) 46.6.11.56 nps ssh:notty (00:00) vmd60532.contaboserver.net narmadan ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net
Tùy chọn -d
sẽ dịch số IP thành tên máy chủ tương ứng. Tên máy chủ có thể cho ta biết về ISP hoặc dịch vụ lưu trữ được sử dụng để thực hiện những phiên đăng nhập không hợp lệ này. Tùy chọn -a
sẽ đặt tên máy chủ trong cột cuối cùng, tạo điều kiện cho việc lọc chưa được áp dụng. Tùy chọn --time-format notime
sẽ chặn thời gian khi có người cố đăng nhập. Lệnh lastb
có thể sẽ mất một chút thời gian để hoàn thành nếu có quá nhiều lần đăng nhập không thành công. Do đó, đầu ra đã bị giới hạn ở mười mục nhập với tùy chọn -n 10
.
Không phải IP từ xa nào cũng có một tên máy chủ liên kết. Vì vậy, DNS ngược sẽ không áp dụng cho chúng và chúng có thể bị loại bỏ. Mặc dù ta có thể viết một biểu thức chính quy để khớp với định dạng dự kiến cho tên máy chủ ở cuối dòng, nhưng có lẽ sẽ đơn giản hơn nếu ta viết một biểu thức chính quy để khớp với một chữ cái trong bảng chữ cái hoặc với một chữ số duy nhất ở cuối dòng. Ví dụ sau đây sẽ cho thấy cách lệnh grep
lấy danh sách ở đầu vào tiêu chuẩn của nó và xóa các dòng không có tên máy chủ:
# lastb -d -a --time-format notime | grep -v '[0-9]$' | head -n 10 nvidia ssh:notty (00:00) vmd60532.contaboserver.net n_tonson ssh:notty (00:00) vmd60532.contaboserver.net nrostagn ssh:notty (00:00) vmd60532.contaboserver.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net pi ssh:notty (00:00) 132.red-88-20-39.staticip.rima-tde.net nps ssh:notty (00:00) vmd60532.contaboserver.net narmadan ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net nominati ssh:notty (00:00) vmd60532.contaboserver.net
Lệnh grep
với tùy chọn -v
sẽ chỉ hiển thị các dòng không khớp với biểu thức chính quy đã cho. Một biểu thức chính quy khớp với bất kỳ dòng nào kết thúc bằng một số (ví dụ: [0-9]$
) sẽ chỉ ghi lại các mục nhập không có tên máy chủ. Do đó, grep -v '[0-9]$'
sẽ chỉ hiển thị các dòng kết thúc bằng tên máy chủ.
Đầu ra có thể được lọc kĩ hơn nữa bằng cách chỉ giữ lại tên miền và loại bỏ các phần khác khỏi mỗi dòng. Lệnh sed
có thể thực hiện điều này bằng một trình thay thế lệnh để thay thế toàn bộ dòng bằng tham chiếu ngược đến tên miền trong đó:
# lastb -d -a --time-format notime | grep -v '[0-9]$' | sed -e 's/.* \(.*\)$/\1/' | head -n 10 vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net 132.red-88-20-39.staticip.rima-tde.net 132.red-88-20-39.staticip.rima-tde.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net vmd60532.contaboserver.net
Dấu ngoặc đơn thoát trong .* \(.*\)$
sẽ nhắc cho sed
nhớ về phần giữa ký tự khoảng trắng cuối cùng và phần cuối của dòng. Trong ví dụ này, phần này được tham chiếu với \1
và được sử dụng để thay thế toàn bộ dòng.
Rõ ràng là hầu hết các máy chủ từ xa đều đã cố gắng đăng nhập nhiều lần, vì thế mà tên miền đã lặp lại. Để chặn các mục nhập lặp lại, trước tiên, chúng cần được sắp xếp (bằng lệnh sort
), sau đó chuyển qua lệnh uniq
:
# lastb -d -a --time-format notime | grep -v '[0-9]$' | sed -e 's/.* \(.*\)$/\1/' | sort | uniq | head -n 10 116-25-254-113-on-nets.com 132.red-88-20-39.staticip.rima-tde.net 145-40-33-205.power-speed.at tor.laquadrature.net tor.momx.site ua-83-226-233-154.bbcust.telenor.se vmd38161.contaboserver.net vmd60532.contaboserver.net vmi488063.contaboserver.net vmi515749.contaboserver.net
Điều này cho ta thấy cách kết hợp các lệnh khác nhau để tạo ra kết quả như mong muốn. Sau đó, danh sách tên máy chủ có thể được sử dụng để viết các quy tắc tường lửa hoặc thực hiện các biện pháp khác để thực thi bảo mật an ninh cho máy chủ.
Bài tập Hướng dẫn
-
Lệnh
last
sẽ hiển thị danh sách người dùng đăng nhập lần cuối, bao gồm cả IP gốc của họ. Lệnhegrep
sẽ được sử dụng như thế nào để lọc đầu ralast
sao cho chỉ hiển thị các lần xuất hiện của địa chỉ IPv4 và loại bỏ mọi thông tin bổ sung trong dòng tương ứng? -
Tùy chọn nào nên được cung cấp cho
grep
để lọc chính xác đầu ra được tạo bởi lệnhfind
được thực thi với tùy chọn-print0
? -
Lệnh
uptime -s
hiển thị ngày cuối cùng mà hệ thống được bật nguồn (như trong2019-08-05 20:13:22
). Kết quả của lệnhuptime -s | sed -e 's/(.*) (.*)/\1/'
sẽ là gì? -
Tùy chọn nào nên được cung cấp cho
grep
để nó đếm các dòng phù hợp thay vì hiển thị chúng?
Bài tập Mở rộng
-
Cấu trúc cơ bản của tệp HTML được bắt đầu bằng các phần tử
html
,head
vàbody
. Ví dụ:<html> <head> <title>News Site</title> </head> <body> <h1>Headline</h1> <p>Information of interest.</p> </body> </html>
Hãy mô tả cách các địa chỉ có thể được sử dụng trong
sed
để chỉ hiển thị phần tửbody
và nội dung của nó. -
Biểu thức
sed
nào sẽ xóa tất cả các thẻ khỏi tài liệu HTML và chỉ giữ lại văn bản được hiển thị? -
Các tệp có phần mở rộng
.ovpn
là rất phổ biến trong việc định cấu hình máy khách VPN vì chúng không chỉ chứa cài đặt mà còn chứa cả nội dung của khóa và chứng nhận cho máy khách. Các khóa và chứng nhận này ban đầu nằm trong các tệp riêng biệt. Vì vậy, chúng cần được sao chép vào tệp.ovpn
. Giả sử ta có đoạn trích sau đây của một mẫu.ovpn
:client dev tun remote 192.168.1.155 1194 <ca> ca.crt </ca> <cert> client.crt </cert> <key> client.key </key> <tls-auth> ta.key </tls-auth>
Giả sử các tệp
ca.crt
,client.crt
,client.key
vàta.key
đều nằm trong thư mục hiện tại thìsed
sẽ sửa đổi cấu hình mẫu như thế nào để thay thế từng tên tệp bằng nội dung của nó?
Tóm tắt
Bài học này nói về hai lệnh Linux quan trọng nhất liên quan đến biểu thức chính quy là grep
và sed
. Các tệp lệnh và lệnh phức hợp sẽ dựa vào grep
và sed
để thực thi nhiều tác vụ lọc và phân tích văn bản. Bài học đã đi qua các bước sau:
-
Cách sử dụng
grep
và các biến thể của nó nhưegrep
vàfgrep
. -
Cách sử dụng
sed
và hướng dẫn bên trong nó để thao tác với văn bản. -
Ví dụ về các ứng dụng của biểu thức chính quy sử dụng
grep
vàsed
.
Đáp án Bài tập Hướng dẫn
-
Lệnh
last
sẽ hiển thị danh sách người dùng đăng nhập lần cuối, bao gồm cả IP gốc của họ. Lệnhegrep
sẽ được sử dụng như thế nào để lọc đầu ralast
sao cho chỉ hiển thị các lần xuất hiện của địa chỉ IPv4 và loại bỏ mọi thông tin bổ sung trong dòng tương ứng?last -i | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
-
Tùy chọn nào nên được cung cấp cho
grep
để lọc chính xác đầu ra được tạo bởi lệnhfind
được thực thi với tùy chọn-print0
?Tùy chọn
-z
hoặc--null-data
như trongfind . -print0 | grep -z expression
. -
Lệnh
uptime -s
hiển thị ngày cuối cùng mà hệ thống được bật nguồn (như trong2019-08-05 20:13:22
). Kết quả của lệnhuptime -s | sed -e 's/(.*) (.*)/\1/'
sẽ là gì?Một lỗi sẽ xảy ra. Theo mặc định, dấu ngoặc đơn phải được thoát để sử dụng tham chiếu ngược trong
sed
. -
Tùy chọn nào nên được cung cấp cho
grep
để nó đếm các dòng phù hợp thay vì hiển thị chúng?Tuỳ chọn
-c
.
Đáp án Bài tập Mở rộng
-
Cấu trúc cơ bản của tệp HTML được bắt đầu bằng các phần tử
html
,head
vàbody
. Ví dụ:<html> <head> <title>News Site</title> </head> <body> <h1>Headline</h1> <p>Information of interest.</p> </body> </html>
Hãy mô tả cách các địa chỉ có thể được sử dụng trong
sed
để chỉ hiển thị phần tửbody
và nội dung của nó.Để chỉ hiển thị
body
, các địa chỉ phải là/<body>/,/<\/body>/
như trongsed -n -e '/<body>/,/<\/body>/p '
. Tùy chọn-n
được cung cấp chosed
để nó không in các dòng theo mặc định, vì thế mà ta nên sử dụng lệnhp
ở cuối biểu thứcsed
để in các dòng phù hợp. -
Biểu thức
sed
nào sẽ xóa tất cả các thẻ khỏi tài liệu HTML và chỉ giữ lại văn bản được hiển thị?Biểu thức
sed
s/<[^>]*>//g
sẽ thay thế bất kỳ nội dung nào bên trong<>
bằng một chuỗi rỗng. -
Các tệp có phần mở rộng
.ovpn
là rất phổ biến trong việc định cấu hình máy khách VPN vì chúng không chỉ chứa cài đặt mà còn chứa cả nội dung của khóa và chứng nhận cho máy khách. Các khóa và chứng nhận này ban đầu nằm trong các tệp riêng biệt. Vì vậy, chúng cần được sao chép vào tệp.ovpn
. Giả sử ta có đoạn trích sau đây của một mẫu.ovpn
:client dev tun remote 192.168.1.155 1194 <ca> ca.crt </ca> <cert> client.crt </cert> <key> client.key </key> <tls-auth> ta.key </tls-auth>
Giả sử các tệp
ca.crt
,client.crt
,client.key
vàta.key
đều nằm trong thư mục hiện tại thìsed
sẽ sửa đổi cấu hình mẫu như thế nào để thay thế từng tên tệp bằng nội dung của nó?Lệnh
sed -r -e 's/(^[^.]*)\.(crt|key)$/cat \1.\2/e' < client.template > client.ovpn
sẽ thay thế bất kỳ dòng nào kết thúc bằng
.crt
hoặc.key
với nội dung của tệp có tên trùng với dòng đó. Tùy chọn-r
sẽ yêu cầused
sử dụng các biểu thức chính quy mở rộng, trong khie
ở cuối biểu thức sẽ yêu cầused
thay thế các kết quả trùng khớp với đầu ra của lệnhcat \1.\2
. Các tham chiếu ngược\1
và\2
sẽ tương ứng với tên tệp và phần mở rộng được tìm thấy trong kết quả trùng khớp.