Linux Commands: sed (Stream Editor) - A Comprehensive Guide
sed là một trình chỉnh sửa dòng (stream editor) xử lý nội dung tệp tin từng dòng một. Nội dung đang được xử lý được lưu trong không gian mẫu (pattern space - bộ đệm), và sau khi xử lý, nó được xuất hoặc sửa đổi theo các tùy chọn được chỉ định. Trừ khi được chuyển hướng để lưu trữ đầu ra, nội dung tệp tin sẽ không thay đổi.
sed chủ yếu được sử dụng để tự động chỉnh sửa một hoặc nhiều tệp tin, đơn giản hóa các thao tác lặp đi lặp lại trên tệp. Nó cũng hỗ trợ biểu thức chính quy; để sử dụng biểu thức chính quy mở rộng, tham số -r nên được thêm vào.
cú pháp: sed [tùy chọn] [lệnh bổ sung] [tệp đầu vào]
Tùy chọn
-n, --quiet, --silent: Vô hiệu hóa tự động in nội dung không gian mẫu -e [lệnh bổ sung], --expression=[lệnh bổ sung hoặc tập lệnh]: Thêm lệnh bổ sung vào danh sách thực thi của chương trình, cho phép nhiều tùy chọn -e -f [tệp lệnh bổ sung], --file=[tệp lệnh bổ sung]: Đọc lệnh bổ sung từ một tệp và thêm vào danh sách thực thi của chương trình -i[hậu tố], --in-place[=hậu tố]: Chỉnh sửa tệp và lưu theo lệnh bổ sung. Nếu có hậu tố, một tệp sao lưu được tạo với tên tệp cộng với hậu tố (tệp có hậu tố là tệp gốc, tệp không có hậu tố là tệp đã sửa đổi) -c, --copy: Khi tổ chức tệp ở chế độ -i, sử dụng sao chép thay vì đổi tên (điều này liên quan đến số inode của tệp) -b, --binary: Mở tệp ở chế độ nhị phân, không xử lý đặc biệt cho CR và LFS (yêu cầu thay đổi và hệ thống tệp kết quả nhật ký), để tương thích với WIN32/CYGWIN/MSDOS/EMX -l N, --line-length=N: Chỉ định độ dài dòng cần thiết cho lệnh bổ sung "l", được hiển thị dưới dạng n-1 chuỗi + \, không có \ ở dòng cuối cùng --posix: Vô hiệu hóa tất cả mở rộng GNU -r, --regexp-extended: Sử dụng biểu thức chính quy trong lệnh bổ sung -s, --separate: Xem xét các tệp như các tệp riêng biệt thay vì một luồng tệp dài liên tục -u, --unbuffered: Tải lượng dữ liệu tối thiểu từ tệp đầu vào và xóa bộ đệm đầu ra thường xuyên hơn -z, --null-data: Tách dòng bằng ký tự NUL
Lệnh bổ sung
: [nhãn]: Đặt nhãn cho lệnh bổ sung b và t
b [nhãn]: Nhảy đến nhãn đã chỉ định; nếu không có nhãn theo sau, nhảy đến cuối lệnh bổ sung, kết thúc thực thi cho dòng đó
t [nhãn]: Nếu lệnh s/// (lệnh thay thế) thực thi thành công, nhảy đến nhãn đã chỉ định; nếu không có nhãn theo sau, nhảy đến cuối lệnh bổ sung, kết thúc thực thi cho dòng đó
T [nhãn]: Ngược với t, nhảy đến nhãn đã chỉ định nếu s/// thất bại; nếu không có nhãn theo sau, nhảy đến cuối lệnh bổ sung, kết thúc thực thi cho dòng đó
Ví dụ: "s/root/xxx/;t a; s/0/1/g;:a" có nghĩa là nếu lệnh thay thế thực thi thành công, lệnh thay thế thứ hai sẽ không được thực thi;
"/^root/b a; s/0/1/g;:a; s/root/xxx/g" có nghĩa là nếu dòng hiện tại bắt đầu bằng root, không thực hiện lệnh thay thế đầu tiên, thực hiện trực tiếp lệnh thay thế thứ hai
# [lệnh bổ sung]: Ghi chú, nếu nó tồn tại trong tệp lệnh bổ sung, nó tiếp tục đến cuối dòng; nếu nó tồn tại trong lệnh bổ sung, nó tiếp tục đến cuối lệnh
{khối lệnh}: Xem xét nhiều lệnh bổ sung như một toàn thể
[lệnh bổ sung1];[lệnh bổ sung2];...: Dấu chấm phẩy tách lệnh bổ sung, cho phép chỉnh sửa nhiều lệnh cùng một lúc
=: In số dòng
a \[văn bản]: Thêm một hoặc nhiều dòng văn bản sau dòng hiện tại, với ký tự thoát \n cho ngắt dòng trong nhiều dòng
i \[văn bản]: Thêm một hoặc nhiều dòng văn bản trước dòng hiện tại, với ký tự thoát \n cho ngắt dòng trong nhiều dòng
c \[văn bản]: Thay thế dòng hiện tại bằng một hoặc nhiều dòng văn bản, với ký tự thoát \n cho ngắt dòng trong nhiều dòng
Ví dụ: "1i \[văn bản]" có nghĩa là thêm văn bản trước dòng đầu tiên; "i \[văn bản]" có nghĩa là thêm văn bản trước mỗi dòng
q [mã thoát]: Thoát ngay lập tức khỏi lệnh sed, giá trị thu được bởi $? là mã thoát đã đặt
Q [mã thoát]: Thoát ngay lập tức khỏi lệnh sed, giá trị thu được bởi $? là mã thoát đã đặt
Lưu ý: Sự khác biệt giữa q và Q là khi tự động in không gian mẫu không bị vô hiệu hóa, q sẽ in không gian mẫu hiện trước khi thoát, trong khi Q thì không
r [tên tệp]: Thêm nội dung của tệp sau dòng hiện tại
R [tên tệp]: Mỗi dòng của tệp được xem như một nội dung riêng biệt, bắt đầu từ dòng được chỉ định, mỗi lần đọc một dòng của tệp đầu vào, thêm nội dung sau dòng đó
Ví dụ: "1r [tên tệp]" có nghĩa là thêm tất cả nội dung tệp sau dòng đầu tiên của tệp đầu vào; "r [tên tệp]" có nghĩa là thêm tất cả nội dung tệp sau mỗi dòng của tệp đầu vào;
"1R [tên tệp]" có nghĩa là thêm dòng đầu tiên của tệp sau dòng đầu tiên của tệp đầu vào, ngay cả khi tệp có nhiều dòng, nó chỉ chạy một lần;
"R [tên tệp]" có nghĩa là bắt đầu từ dòng đầu tiên của tệp đầu vào, nối nội dung dòng tương ứng của tệp cho mỗi dòng cho đến khi một trong tệp đầu vào hoặc nội dung tệp kết thúc;
"2,4R [tên tệp]" có nghĩa là từ dòng thứ hai đến thứ tư của tệp đầu vào, nối dòng thứ nhất đến thứ ba của nội dung tệp cho mỗi dòng.
d: Xóa không gian mẫu
D: Tương tự như d (có sự khác biệt, nhưng không chắc cách kích hoạt)
h|H: Sao chép hoặc nối nội dung không gian mẫu vào bộ đệm trong bộ nhớ
g|G: Sao chép hoặc nối bộ đệm trong bộ nhớ vào không gian mẫu
l: Hiển thị dòng hiện tại một cách trực quan, không hủy bỏ in mặc định, ký tự thoát sẽ được hiển thị dưới dạng $
l [độ dài]: Hiển thị dòng hiện tại một cách trực quan, chỉ định độ dài để in mỗi lần, và \ được sử dụng làm nối dòng (được tính trong độ dài)
n|N: Đọc hoặc nối dòng tiếp theo vào không gian mẫu, sự khác biệt là đọc sẽ ghi đè nội dung hiện có, trong khi nối thì không
p: In toàn bộ nội dung trong không gian mẫu
P: In dòng đầu tiên trong không gian mẫu
s/[nội dung tìm kiếm (biểu thức chính quy)]/[nội dung thay thế]: Cố gắng khớp nội dung tìm kiếm với nội dung trong không gian mẫu, nếu thành công, thay thế phần khớp. Nội dung thay thế có thể sử dụng ký tự đặc biệt & để đại diện cho nội dung khớp trong không gian mẫu,
ký tự thoát đặc biệt \1 đến \9 biểu thị các biểu thức con tương ứng được khớp trong biểu thức chính quy. (s/[nội dung tìm kiếm]/[nội dung thay thế]/g có thể thay thế tất cả nội dung khớp)
w [tên tệp]: Ghi nội dung không gian mẫu hiện tại vào tệp được chỉ định
W [tên tệp]: Ghi dòng đầu tiên của không gian mẫu hiện tại vào tệp được chỉ định
x: Trao đổi nội dung của bộ đệm trong bộ nhớ và không gian mẫu
Ví dụ
Lưu ý: Không gian mẫu có thể được xem như bộ đệm mà sed đọc nội dung tệp mỗi lần, mặc định đọc một dòng tại một thời điểm.
Chuẩn bị hai tệp thử nghiệm:
[root@youxi1 ~]# vim readFile root:0:0:root:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass [root@youxi1 ~]# vim a.txt 12345 67890
1) Xem các dòng 2 đến 4 của tệp readFile
[root@youxi1 ~]# sed -e "2,4p" readFile -n // Tùy chọn -e là tùy chọn mặc định, có thể không viết abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass [root@youxi1 ~]# sed "2,4p" readFile // Nếu không có tùy chọn -n, sed sẽ tự động in nội dung không gian mẫu root:0:0:root:123456:password abc:1:1:abc:password1 abc:1:1:abc:password1 xyz:2:2:abc:password2 xyz:2:2:abc:password2 root:3:4:abc:pass root:3:4:abc:pass
2) Tùy chọn -i và -c, đổi tên và sao chép
# Khi không có tùy chọn -c, tùy chọn -i đổi tên tệp gốc thành tệp sao lưu [root@youxi1 ~]# ls -i readFile // Kiểm tra số inode của readFile 33575417 readFile [root@youxi1 ~]# sed -i.bak "1,2p" readFile -n // Sử dụng tùy chọn -i để chỉnh sửa và lưu tệp [root@youxi1 ~]# ls -i readFile // Ta có thể thấy số inode khác với tệp gốc 33574999 readFile [root@youxi1 ~]# cat readFile // Nội dung cũng khác với tệp gốc root:0:0:root:123456:password abc:1:1:abc:password1 [root@youxi1 ~]# ls -i readFile.bak // Tệp sao lưu có cùng số inode với tệp gốc 33575417 readFile.bak [root@youxi1 ~]# cat readFile.bak // Nội dung giống với tệp gốc root:0:0:root:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass # Khi sử dụng tùy chọn -i kết hợp với tùy chọn -c [root@youxi1 ~]# sed -i.cp "1,2p" readFile.bak -n -c [root@youxi1 ~]# ls -i readFile.bak // Ta có thể thấy số inode giống với tệp gốc 33575417 readFile.bak [root@youxi1 ~]# cat readFile.bak // Nội dung khác với tệp gốc root:0:0:root:123456:password abc:1:1:abc:password1 [root@youxi1 ~]# ls -i readFile.bak.cp // Tệp sao lưu có số inode khác với tệp gốc 34037099 readFile.bak.cp [root@youxi1 ~]# cat readFile.bak.cp // Nội dung giống với tệp gốc root:0:0:root:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass
3) Lệnh bổ sung a \[văn bản\], i \[văn bản\], c \[văn bản\]
[root@youxi1 ~]# rm -rf readFile readFile.bak [root@youxi1 ~]# mv readFile.bak.cp readFile [root@youxi1 ~]# cat readFile root:0:0:root:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass [root@youxi1 ~]# sed "1a \add" readFile // Thêm dưới dòng đầu tiên root:0:0:root:123456:password add abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass [root@youxi1 ~]# sed "1i \add" readFile // Thêm trên dòng đầu tiên add root:0:0:root:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass [root@youxi1 ~]# sed "1c \add" readFile // Thay thế dòng đầu tiên add abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass [root@youxi1 ~]# sed "1c \add\nabc\t123 456" readFile // Ký tự thoát cho ngắt dòng \n và tab \t add abc 123 456 abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass
4) Lệnh bổ sung =, in số dòng
[root@youxi1 ~]# sed "=" readFile 1 root:0:0:root:123456:password 2 abc:1:1:abc:password1 3 xyz:2:2:abc:password2 4 root:3:4:abc:pass
5) Lệnh bổ sung d
[root@youxi1 ~]# sed "1,2d" readFile xyz:2:2:abc:password2 root:3:4:abc:pass
6) Lệnh bổ sung s/[nội dung tìm kiếm]/[nội dung thay thế]/(g)
[root@youxi1 ~]# sed "s/root/xxx/" readFile // Thay thế lần khớp đầu tiên xxx:0:0:root:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 xxx:3:4:abc:pass [root@youxi1 ~]# sed "s/root/xxx/g" readFile // Thay thế tất cả các lần khớp xxx:0:0:xxx:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 xxx:3:4:abc:pass [root@youxi1 ~]# sed "s/a.*p/1234/" readFile // Khớp biểu thức chính quy và thay thế root:0:0:root:123456:password 1234assword1 xyz:2:2:1234assword2 root:3:4:1234ass [root@youxi1 ~]# sed "s/a.*p/&1234/" readFile // Khớp biểu thức chính quy, giữ nguyên và thêm thay thế root:0:0:root:123456:password abc:1:1:abc:p1234assword1 xyz:2:2:abc:p1234assword2 root:3:4:abc:p1234assBạn cũng có thể thêm một số trước s để chỉ định bắt đầu từ dòng nào để tìm kiếm.
7) Tùy chọn -r, sử dụng biểu thức chính quy để khớp các dòng cụ thể
[root@youxi1 ~]# sed -r "/^root/i \1234" readFile // Tìm dòng được chỉ định, thêm nội dung trên nó
1234
root:0:0:root:123456:password
abc:1:1:abc:password1
xyz:2:2:abc:password2
1234
root:3:4:abc:pass
[root@youxi1 ~]# sed "/^.*abc/{s/^.*$/&\tName/}" readFile // Tùy chọn -r có thể được bỏ qua
root:0:0:root:123456:password
abc:1:1:abc:password1 Name
xyz:2:2:abc:password2 Name
root:3:4:abc:pass Name
[root@youxi1 ~]# sed "/^.*abc/s/^.*$/&\tName/" readFile // Ngay cả {} cũng có thể được bỏ qua, nhưng không nên vì không dễ hiểu
root:0:0:root:123456:password
abc:1:1:abc:password1 Name
xyz:2:2:abc:password2 Name
root:3:4:abc:pass Name
8) Lệnh bổ sung q, Q
[root@youxi1 ~]# sed "/^.*abc/q" readFile root:0:0:root:123456:password abc:1:1:abc:password1 [root@youxi1 ~]# sed "/^.*abc/Q" readFile root:0:0:root:123456:password
9) Lệnh bổ sung r [tên tệp], R [tên tệp]
[root@youxi1 ~]# sed "/^root/r a.txt" readFile root:0:0:root:123456:password 12345 67890 abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass 12345 67890 [root@youxi1 ~]# sed "/^root/R a.txt" readFile root:0:0:root:123456:password 12345 abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass 67890
10) Lệnh bổ sung n, N, p, P, w, W
Đầu tiên, điều quan trọng là hiểu n (đọc dòng tiếp theo vào không gian mẫu), N (nối dòng tiếp theo vào không gian mẫu), và hành động mặc định của việc in không gian mẫu (chuẩn bị đọc dòng tiếp theo, kết thúc lệnh sed). Lưu ý: Các dòng đọc hoặc nối vào không gian mẫu không còn được đọc bởi các lệnh sed.[root@youxi1 ~]# sed "n;p" readFile root:0:0:root:123456:password // Chuẩn bị thực hiện lệnh bổ sung n, kích hoạt in mặc định không gian mẫu hiện tại. Sau khi n thực thi, nội dung không gian mẫu là dòng thứ hai abc:1:1:abc:password1 // Thực hiện lệnh bổ sung p, in không gian mẫu hiện tại, nội dung không gian mẫu không thay đổi abc:1:1:abc:password1 // Lệnh sed chuẩn bị đọc dòng tiếp theo, kích hoạt in mặc định không gian mẫu hiện tại. Sau khi đọc dòng tiếp theo, nội dung không gian mẫu là dòng thứ ba xyz:2:2:abc:password2 // Chuẩn bị thực hiện lệnh bổ sung n, kích hoạt in mặc định không gian mẫu hiện tại. Sau khi n thực thi, nội dung không gian mẫu là dòng thứ tư root:3:4:abc:pass // Thực hiện lệnh bổ sung p, in không gian mẫu hiện tại, nội dung không gian mẫu không thay đổi root:3:4:abc:pass // Lệnh sed kết thúc, in không gian mẫu hiện tại (hành động này để làm sạch không gian mẫu?) [root@youxi1 ~]# sed "N;p" readFile root:0:0:root:123456:password abc:1:1:abc:password1 // Thực hiện lệnh bổ sung N, nội dung không gian mẫu là dòng thứ nhất và thứ hai; thực hiện lệnh bổ sung p, in không gian mẫu hiện tại root:0:0:root:123456:password abc:1:1:abc:password1 // Lệnh sed chuẩn bị đọc dòng tiếp theo, kích hoạt in mặc định không gian mẫu hiện tại. Sau khi đọc dòng tiếp theo, nội dung không gian mẫu là dòng thứ ba xyz:2:2:abc:password2 root:3:4:abc:pass // Thực hiện lệnh bổ sung N, nội dung không gian mẫu thay đổi từ dòng thứ ba thành dòng thứ ba và thứ tư; thực hiện lệnh bổ sung p, in không gian mẫu hiện tại xyz:2:2:abc:password2 root:3:4:abc:pass // Lệnh sed kết thúc, in không gian mẫu hiện tại (hành động này để làm sạch không gian mẫu?)Tiếp theo, hiểu p (in không gian mẫu hiện tại) và P (in dòng đầu tiên trong không gian mẫu). Với sự hiểu biết về n và N, những điều này cũng dễ hiểu.
[root@youxi1 ~]# sed "N;p" readFile -n root:0:0:root:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass [root@youxi1 ~]# sed "N;P" readFile -n root:0:0:root:123456:password xyz:2:2:abc:password2Cuối cùng là w (lưu không gian mẫu hiện tại vào tệp được chỉ định) và W (lưu dòng đầu tiên của không gian mẫu hiện tại vào tệp được chỉ định), sự khác biệt với p và P là chúng không in, trực tiếp lưu vào tệp. Hiểu p và P, những điều này cũng đơn giản.
[root@youxi1 ~]# sed "N;w b.txt" readFile -n [root@youxi1 ~]# sed "N;W c.txt" readFile -n [root@youxi1 ~]# cat b.txt root:0:0:root:123456:password abc:1:1:abc:password1 xyz:2:2:abc:password2 root:3:4:abc:pass [root@youxi1 ~]# cat c.txt root:0:0:root:123456:password xyz:2:2:abc:password2