Sắp xếp trong Bash shell

Sắp xếp là 1 tác vụ phổ biến mà chúng ta sẽ gặp phải khi làm việc với các tập tin văn bản. Để sắp xếp trong Bash shell, chúng ta sử dụng lệnh sort  để thực hiện các tác vụ sắp xếp trên các tập tin văn bản và stdin. Thường thì chúng ta có thể ghép cặp lệnh sort với nhiều lệnh khác để cho ra kết quả chúng ta mong muốn. uniq là 1 lệnh khác mà thường được dùng cùng với lệnh sort. Nó giúp chúng ta trích xuất ra các dòng duy nhất (xuất hiện 1 lần) hoặc các dòng trùng lặp từ 1 tập tin văn bản hoặc từ stdin.


Trong bài viết này, chúng ta sẽ cùng tìm hiểu cách sử dụng lệnh sort  và uniq để thực hiện việc việc sắp xếp trong Bash shell.


1. sort


Lệnh sort nhận dữ liệu đầu vào là tên tập tin hoặc dữ liệu nhập từ stdin, xuất ra kết quả bằng cách in ra stdout. Trong trường hợp chúng ta muốn xuất ra kết quả vào tập tin, chúng ta có thể sử dụng chuyển hướng.


1.1. Cú pháp


Lệnh sort có thể nhận dữ liệu đầu vào là 1 hoặc nhiều tập tin cùng 1 lúc. Trong trường hợp sắp xếp nhiều tập tin cùng lúc, sort sẽ nối tất cả nội dung của các tập tin được truyền vào và in ra kết quả đã được sắp xếp trên nội dung được nối vào đó.


$ sort file1 file2 file3 ...

vd:


file1.txt a 1  dfile2.txt c 2 b 3$ sort file1.txt file2.txt1 2 3 a b c d

Mặc định thì lệnh sort sẽ xuất kết quả ra màn hình. Trong trường hợp chúng ta muốn lưu kết quả sắp xếp vào tập tin, sử dụng chuyển hướng như sau:


$ sort file1 file2 file3 ... > sorted.txt

1.2. Sắp xếp theo chuỗi


Mặc định, sort sẽ sắp xếp nội dung tập tin dựa trên việc so sánh chuỗi và sắp xếp theo chiều tăng dần.


So sánh chuỗi là phương thức chúng ta sẽ so sánh lần lượt từng ký tự trong chuỗi theo chiều từ trái sang phải. Tại 1 vị trí nhất định, nếu:


2 ký tự tương ứng của 2 chuỗi bằng nhau => So sánh ký tự tiếp theo.


2 ký tự không bằng nhau => Dừng so sánh và trả về kết quả.


Độ lớn của các ký tự dựa vào giá trị của ký tự trong bảng mã mà hệ thống đang sử dụng, đó có thể là bảng mã ASCII hoặc Unicode.


Ví dụ về so sánh chuỗi:


Giả sử ta có 2 chuỗi như sau:


string1=”qwerty”


string2=”qaz”


Trước hết, ta chuyển 2 chuỗi trên sang dạng mảng ký tự như sau:


string1=(q w e r t y)


string2=(q a z)


Tiến hành so sánh giá trị của 2 mảng như sau:

Bước 1: So sánh ký tự thứ 1 trong mảng


string1[0]=”q”


string2[0]=”q”


=> string1[0] = string2[0]


=> Chuyển sang bước thứ 2


Bước 2: So sánh ký tự thứ 2 trong mảng


string1[1]=”w”


string2[2]=”a”


=> w > a


=> string1 > string2


=> Dừng thuật toán và trả về kết quả là string1 > string2


Nếu chạy ví dụ trên với sort, ta được kết quả:


string.txt qwerty qaz$ sort string.txt qaz qwerty

1.3. Sắp xếp theo số


Như đã nói ở trên, mặc định thì sort sẽ so sánh nội dung theo kiểu dữ liệu chuỗi. Nếu chúng ta muốn so sánh theo kiểu dữ liệu số, sử dụng như sau:


$ sort -n file

vd:


number.txt 1000 0.1 1.23 -1 -100$ sort -n number.txt -100 -1 0.1 1.23 1000

Lưu ý, trong trường hợp tập tin của chúng ta vừa có cả số và chuỗi, sort sẽ quy định rằng:


Dữ liệu chuỗi luôn lớn hơn các số âm và số 0.


Dữ liệu chuỗi luôn nhỏ hơn các số lớn hơn 0.


và áp dụng cách so sánh chuỗi đối với các dữ liệu chuỗi này, trong khi đó, sort sẽ áp dụng các so sánh dữ liệu số như chúng ta đã đề cập đối với các dữ liệu số.


vd:


numberstring.txt 1000 qazxsw 0.1 1.23 hello -1 aloha -100 qwerty qaz 0 0.0000000000001$ sort -n numberstring.txt -100 -1 0 aloha hello qaz qazxsw qwerty 0.0000000000001 0.1 1.23 1000

1.4. Sắp xếp giảm dần


Để sắp xếp nội dung theo chiều giảm dần với sort, sử dụng cú pháp sau:


$ sort -r file

vd:


reverse.txt 1 2 3$ sort -r reverse.txt 3 2 1

1.5. Sắp xếp theo tháng


Để sắp xếp các tháng trong năm như Jan, Feb, March … sử dụng cú pháp sau:


$ sort -M file

vd:


month.txt feb july dec jan$ sort -M month.txt jan feb july dec

1.6. Tìm kiếm dòng duy nhất


Để tìm kiếm những dòng duy nhất, tức là chỉ xuất hiện 1 lần trong tập tin, sử dụng cú pháp sau:


$ sort file1 file2 file3 .. | uniq

1.7. Kiểm tra tập tin đã được sắp xếp chưa?


Để kiểm tra nội dung của tập tin đã được sắp xếp chưa, ta sử dụng cú pháp sau:


$ sort -c file

hoặc


$ sort -C file

Trong đó:


-c: trả về kết quả là dòng đầu tiên không theo thứ tự.


vd: với tập tin numberstring.txt ở trên


$ sort -c numberstring.txt sort: numberstring.txt:3: disorder: 0.1

-C: trả về 0 nếu tập tin đã được sắp xếp, khác 0 nếu chưa được sắp xếp.


vd:


$ sort -C numberstring.txt $ echo $? 1

1.8. Sắp xếp theo khóa hoặc cột


Chúng ta có thể sắp xếp theo cột với sort nếu chúng ta cần sắp xếp 1 văn bản có dạng như sau:


$ cat data.txt 1    mac    2000 2    winxp    4000 3    bsd    1000 4    linux    1000

Để sắp xếp theo cột, chúng ta dùng đối số -k theo sau là số thứ tự của cột.


vd:


Để sắp xếp theo cột số thứ tự (cột số 1) theo chiều giảm dần, ta sử dụng như sau:


# Sort reverse by column1 $ sort -nrk 1 data.txt 4    linux    1000 3    bsd    1000 2    winxp    4000 1    mac    2000

Để sắp xếp theo cột thứ 2:


$ sort -k 2 data.txt 3    bsd    1000 4    linux    1000 1    mac    2000 2    winxp    4000

Thông thường thì các khóa là các cột trong 1 tập tin văn bản. Các cột được phân tách nhau bởi ký tự khoảng trắng. Nhưng trong 1 vài trường hợp, chúng ta có thể cần chỉ rõ các khóa như là 1 nhóm các ký tự trong 1 dãy số – ký tự cho trước (ví dụ key1 = character4 – character8). Trong những trường hợp như vậy nơi khóa được chỉ rõ 1 cách tường minh như 1 dãy các ký tự, chúng ta có thể chỉ rõ khóa như 1 dãy ký tự với vị trí của ký tự bắt đầu khóa và vị trí của ký tự kết thúc khóa như sau:


$ cat data.txt 1010hellothis 2189ababbba 7464dfddfdfd$ sort -nk 2,3 data.txt

Trong ví dụ trên, khóa mà chúng ta sử dụng có chiều dài 2 ký tự, bắt đầu từ ký tự thứ 2 và kết thúc ở ký tự thứ 3.


$ sort -nk 2,3 data.txt 1010hellothis 2189ababbba 7464dfddfdfd

Để sử dụng ký tự đầu tiên như là khóa, sử dụng:


$ sort -nk 1,1 data.txt

2. uniq


uniq là 1 lệnh được dùng để tìm ra các chuỗi duy nhất (chỉ xuất hiện 1 lần) từ dữ liệu nhập vào (stdin hoặc từ 1 tập tin) bằng việc loại bỏ các dòng trùng lặp. Nó cũng có thể được dùng để tìm ra các dòng trùng lặp từ dữ liệu nhập vào.


uniq chỉ có thể áp dụng cho các dữ liệu đã được sắp xếp. Do vậy, uniq sẽ luôn luôn được dùng cùng với lệnh sort bằng việc sử dụng ổng dẫn – pipe (|) hoặc sử dụng 1 tập tin được sắp xếp như đầu vào.


Ống dẫn – pipe – là kỹ thuật ghép nhiều lệnh vào 1 dòng và trong đó kết quả của lệnh trước sẽ là dữ liệu đầu vào của lệnh tiếp theo.


vd:


$ cat file.txt | grep "hello"

=> Đọc tập tin file.txt và tìm chữ “hello”


Việc tìm ra các dòng duy nhất trong uniq được thực hiện như sau:


$ cat sorted.txt bash foss hack hack$ uniq sorted.txt bash foss hack

hoặc


$ sort unsorted.txt | uniq

Để hiển thị chỉ những dòng duy nhất (những dòng mà không được lặp lại hoặc trùng lặp trong dữ liệu đầu vào), thực hiện như sau:


$ uniq -u sorted.txt bash foss

hoặc


$ sort unsorted.txt | uniq -u

Để đếm số lần mà mỗi dòng xuất hiện trong tập tin, sử dụng cú pháp sau:


$ sort unsorted.txt | uniq -c 1 bash 1 foss 2 hack

Để tìm những dòng trùng lặp, sử dụng cú pháp sau:


$ sort unsorted.txt | uniq -d hack

Để chỉ rõ các khóa, chúng ta có thể sử dụng kết hợp các đối số -s và -w:


-s: chỉ rõ số ký tự N đầu tiên được bỏ qua.


-w: chỉ rõ số ký tự tối đa được so sánh.


Khóa so sánh này được dùng như chỉ mục  cho lệnh uniq như sau:


$ cat data.txt u:01:gnu d:04:linux u:01:bash u:01:hack$ sort data.txt | uniq -s 2 -w 2 d:04:linux u:01:bash

Trong ví dụ trên, chúng ta sử dụng 2 ký tự ở vị trí số 2 và 3 làm khóa so sánh thay cho toàn bộ dòng.


Chúng ta hoàn thành bài tìm hiểu về cách sắp xếp trong Bash shell tại đây.


Nhận xét

Bài đăng phổ biến