The stream editor sed
Nguồn: Tổng hợp từ cuốn sách “The Unix Programming Environment” của Brian W. Kernighan và Rob Pike.
Bài viết này giới thiệu những chức năng cơ bản nhất của sed, một chương trình xử lí văn bản cực mạnh trong Unix. Bài viết có sử dụng (mà không giải thích chi tiết) một số regular expression (cơ bản) và một số lệnh Unix (cũng cơ bản
)
Cú pháp chung của sed
Cú pháp chung của một lệnh sed là
sed 'danh sách các lệnh' 'danh sách các file đầu vào'
sed sẽ đọc từng dòng của các file đầu vào và thực hiện từng lệnh trong danh sách các lệnh đối với các dòng đó. Sau đó, sed ghi dữ liệu ra vào thiết bị đầu ra chuẩn.
Chẳng hạn, chúng ta có thể thay tất cả các từ UNIX trong một file thành UNIX(TM) bằng câu lệnh sau:
sed 's/UNIX/UNIX(TM)/g' filename
Khi thực hiện lệnh này, sed sẽ:
- Đọc vào từng dòng của filename
- Đối với mỗi dòng đọc vào, sed sẽ thực hiện lệnh s/UNIX/UNIX(TM)/g, tức là thay thế (s = substitute) tất cả (g = global) các từ UNIX bởi UNIX(TM).
s (substitute) là một lệnh của ed, chương trình tiền thân của sed.
Chú ý: sed không thay đổi nội dung của file đầu vào.
Chúng ta luôn sử dụng dấu nháy đơn (single quote) để bao quanh các lệnh của sed nhằm tránh trường hợp các kí tự đặc biệt bị dịch thành ý nghĩa khác bởi shell.
Sau đây là 1 số lệnh sed thú vị!!!
Cắt file thành các dòng, mỗi dòng một từ
sed 's/[ ][ ]*/\ (enter)
> /g' filename
Chú ý: Dấu > là dấu nhắc của shell, không phải gõ vào
Bản chất của lệnh này là thay thế một hoặc nhiều kí tự blank bởi một kí tự xuống dòng. Tương tự, chúng ta có thể dãn khoảng cách giữa các dòng thêm một dòng trống bằng lệnh
sed 's/$/\ (enter)
> /g' filename
Bản chất của lệnh này là thay thế các kí tự kết thúc mỗi dòng ($) bởi một kí tự xuống dòng. Chú ý rằng lệnh này thao tác trên cả các dòng trống. Để lệnh chỉ thao tác trên các dòng khác trống (tức là mỗi lần thực hiện lệnh chỉ một dòng trống được chèn vào mà thôi), ta dùng lệnh sau ( /./ biểu diễn các dòng không trống)
sed '/./s/$\ (enter)
> /g' filename
In các dòng từ thứ 1 đến thứ 10 (Chú ý: số MỘT, không phải chữ LỜ)
sed -n '1,10p' filename
Xóa các dòng từ thứ 1 dến thứ 10
sed '1,10d' filename
Xóa các dòng chứa xâu “thing”
sed '/thing/d' filename
Xóa file từ dòng thứ 1 đến dòng trống đầu tiên. Chú ý /^$/ biểu diễn các dòng mà kí tự cuối dòng ($) xuất hiện ngay sau kí tự đầu dòng (^), tức là các dòng trống
sed '1,/^$/d' filename
Xóa dòng cuối dùng
sed '$d' filename
Một hạn chế của sed là không có khả năng biểu diễn các dòng một cách tương đối, tức là, chúng ta KHÔNG thể dùng lệnh sau đây để xóa dòng nằm ngay trước dòng cuối cùng của file
sed '$-1d' filename
Lệnh q
Lệnh q in ra các dòng từ dòng thứ nhất cho đến dòng đầu tiên thỏa mãn một tính chất nào đó. Chúng ta có thể viết lại lệnh in ra các dòng từ thứ 1 đến thứ 10 ở phần trên bằng lệnh q như sau
sed '10q' filename
Lệnh này tương đương với lệnh sau đây
head -10 filename
In ra các dòng từ dòng thứ nhất đến dòng đầu tiên chứa xâu “thing”
sed '/thing/q' filename
In ra các file trong thư mục hiện thời mới hơn file kien ![]()
ls -t | sed '/^kien$/q'
Bản chất của lệnh trên là: ls -t in ra các file trong thư mục hiện thời theo thứ tự từ mới đến cũ, mỗi tên file nằm trên một dòng. Đầu ra này được chuyển sang cho sed xử lí, sed in ra các dòng từ dòng thứ nhất cho đến dòng đầu tiên chỉ chứa xâu “kien” (là tên file). Chú ý rằng /^kien$/ biểu diễn cho các dòng bao gồm kí tự đầu dòng (^), xâu “kien”, kí tự cuối dòng ($), tức là các dòng chỉ chứa xâu “kien”. Sở dĩ phải dùng pattern /^kien$/ thay vì /kien/ vì có thể tên một file nào đó lại là một phần của tên một file khác( kien với kienabc chẳng hạn)
Tương tự, lệnh sau in ra các file trong thư mục hiện thời cũ hơn file kien
ls -tr | sed '/^kien$/q'
Tham số -r (revert) yêu cầu ls đảo ngược thứ tự sắp xếp, từ cũ đến mới.
Xử lí các dòng KHÔNG thỏa mãn một tính chất nào đó
Các lệnh ở trên đều xử lí trên các dòng thỏa mãn một tính chất nào đó. Chúng ta có thể thực hiện thao tác ngược lại, xử lí các dòng không thoả mãn một tính chất bằng cách sử dụng dấu chấm than ! (exclamation mark)
In ra các dòng không chứa xâu “thing” (chú ý tham số -n)
sed -n '/thing/!p' filename
Xóa các dòng không chứa xâu “thing”
sed '/thing/!d' filename
Thực hiện nhiều xử lí cùng lúc
sed cho phép thực hiện nhiều xử lí trong cùng một câu lệnh, các thao tác xử lí được phân cách bằng kí tự xuống dòng (enter)
Lệnh sau đây thay thế xâu “thing” trong các dòng bằng xâu “things” đồng thời thay thế xâu “hello” trong các dòng bằng xâu “hellos” (chú ý: > là dấu nhắc của shell, không phải gõ vào)
sed 's/thing/things/ (enter)
> s/hello/hellos' filename
In đầu ra của sed ra các file
Chúng ta có thể in đầu ra của sed ra cá file bằng hai cách sau đây:
Cách 1: Chuyển hướng đầu ra từ đầu ra chuẩn (màn hình) thành file
Ví dụ: Ghi ra một file các dòng chứa xâu “thing”
sed -n '/thing/p' filename >outfile
Cách 2: Dùng lệnh w
Lệnh ghi ra một file các dòng chứa xâu “thing” bây giờ được thực hiện như sau
sed '/thing/w outfile' filename
Kết hợp với dấu chấm than !, chúng ta có câu lệnh khá thú vị sau đây:
sed '/thing/w outfile1 (enter)
> /thing/!w outfile2' filenames
Câu lệnh trên ghi các dòng chứa xâu “thing” vào outfile1 và ghi các dòng không chứa xâu “thing” vào outfile2.
Một ví dụ khác, lệnh sau đây thay thế tất cả các xâu “thing” trong file bằng xâu “things” và ghi đầu ra ra outfile
sed 's/thing/things/gw outfile' filenames
Đặt các lệnh sed trong file đầu vào
Từ trước đến nay các lệnh sed luôn được gõ trực tiếp trên dòng lệnh, tuy nhiên đối với các lệnh được sử dụng thường xuyên chúng ta nên đặt chúng vào một file đầu vào, sau đó thực hiện sed với tham số -f.
Ví dụ, để thay thế tất các xâu “thing” trong một file bằng xâu “things”, chúng ta có thể làm một cách dài dòng như sau:
Bước 1: Tạo file đầu vào chứa lệnh sed
echo 's/thing/things/g' >infile
Bước 2: Chạy sed với tham số -f
sed -f infile filename
Truyền tham số vào lệnh sed
Ở phần trên chúng ta đã biết lệnh sau đây in ra các file trong thư mục hiện thời mới hơn file ‘kien’
ls -t | sed '/^kien$/q'
Tuy nhiên nếu chúng ta muốn chạy câu lệnh này nhiều lần, mỗi lần với một tên file khác nhau, thì cách tốt nhất là đặt lệnh này vào trong một shell file và truyền tên file (kien,…) vào như một tham số của shell, ví dụ:
newer kien
Nội dung của file newer sẽ như sau
#newer file: list files newer than file
ls -t | sed '/^'$1'$/q'
Các dấu nháy đơn đảm bảo rằng kí tự $ của lệnh sed không bị dịch bởi shell. Trái lại, $1 sẽ bị shell thay thế bởi tham số thứ nhất trên dòng lệnh. Một cách khác để đảm bảo kí tự $ của sed không bị dịch bởi shell là dùng kí tự backslash (\). Khi đó nội dung file newer sẽ như sau (chú ý dấu nháy kép)
#newer file: list files newer than file
ls -t | sed "/^$1\$/q"
Tương tự chúng ta có file older như sau:
#older file: list files older than file
ls -tr | sed '/^'$1'$/q'
Hoặc
#older file: list files older than file
ls -tr | sed "/^$1\$/q"
Kết luận
Lệnh sed còn rất nhiều tính năng phức tạp khác như kiểm tra điều kiện, rẽ nhánh, vòng lặp…Tuy nhiên những tính năng được trình bày ở trên là cơ bản nhất và được sử dụng thường xuyên nhất. Điểm mạnh của sed là khả năng xử lí dữ liệu vào có độ dài tùy ý với tốc độ nhanh. Điểm yếu của sed là khả năng nhớ dữ liệu kém và không xử lí được dữ liệu số. Những điểm yếu này được khắc phục bởi awk.
Tài liệu tham khảo
- Sách: “The Unix Programming Environment” của Brian W. Kernighan và Rob Pike
- Sách: sed & awk by O’Reilly
- Manual Page: Dùng lệnh man sed
Credit: http://www.openandfree.org
--YHT
Tại sao Fire
Băn khoăn gi


Category : 
