Bước tới nội dung

join (Unix)

Bách khoa toàn thư mở Wikipedia
join
Tác giả gốcDouglas McIlroy
Nhà phát triểnAT&T Bell Laboratories
Phát hành lần đầu1979
Hệ điều hànhUnix, các hệ điều hành giống Unix
Thể loạiLệnh

join là một lệnh trong Unix và các hệ điều hành giống Unix, có chức năng ghép các dòng của hai tập tin văn bản đã được sắp xếp dựa trên một trường chung. Lệnh tương tự như toán tử join trong cơ sở dữ liệu quan hệ nhưng đối tượng là các tập tin văn bản. Chuẩn POSIX và các trang hướng dẫn của Unix đều mô tả join là "toán tử cơ sở dữ liệu quan hệ" (relational database operator).[1][2]

Lịch sử

[sửa | sửa mã nguồn]

Lệnh join xuất hiện lần đầu trong Version 7 Unix của AT&T, phát hành năm 1979.[3][4] Tác giả của lệnh là Douglas McIlroy, người cũng viết các tiện ích như diff, echo và spell tại Bell Labs.[4][5]

Phiên bản trong Version 7 nhận các tùy chọn -a, -e, -j, -o và -t, và chỉ cho phép tập tin thứ nhất là - (đọc từ đầu vào chuẩn). Phần "BUGS" của trang hướng dẫn này ghi nhận rằng quy ước của join, sort, comm, uniq, look và awk không thống nhất với nhau.[2]

Lệnh được đưa vào tiêu chuẩn của X/Open từ Issue 2 và hiện là một phần của POSIX và Single UNIX Specification. Trong quá trình chuẩn hóa, một số thay đổi được bổ sung so với các bản cài đặt lịch sử:[1]

  • Tùy chọn -v được thêm vào để chỉ xuất những dòng không ghép cặp được, tương tự tùy chọn -v của grep.
  • Trường 0 trong danh sách của -o (đại diện cho trường join) được lấy từ phiên bản join của Tenth Edition Unix, nhằm hỗ trợ phép "full join" hay "outer join" trong lý thuyết cơ sở dữ liệu quan hệ.
  • Khả năng dùng - cho tập tin thứ hai được thêm vào cho đầy đủ.
  • Các tùy chọn -j, -j1, -j2 và dạng -o nhận nhiều đối số bị loại khỏi tiêu chuẩn từ Issue 6, được thay bằng -1 và -2.

Phiên bản join trong GNU coreutils do Mike Haertel viết.[6] Các hệ điều hành họ BSD như FreeBSD và OpenBSD có bản cài đặt riêng, tuân theo POSIX và vẫn giữ các tùy chọn lịch sử để tương thích với những shell script cũ.[7][3]

Theo POSIX, cú pháp của lệnh là:[1]

join [-a số_tập_tin | -v số_tập_tin] [-e chuỗi] [-o danh_sách] [-t ký_tự] [-1 trường] [-2 trường] tập_tin1 tập_tin2

Nếu một trong hai tập tin được ghi là -, lệnh sẽ đọc từ đầu vào chuẩn. Kết quả được ghi ra đầu ra chuẩn; để lưu vào tập tin cần dùng tái định hướng của shell.

Hoạt động

[sửa | sửa mã nguồn]

Lệnh join thực hiện phép nối bằng (equality join) trên hai tập tin. "Trường join" là trường được dùng để so sánh trong mỗi tập tin, mặc định là trường đầu tiên của mỗi dòng. Với mỗi cặp dòng (một dòng từ mỗi tập tin) có trường join bằng nhau, lệnh ghi ra một dòng gồm trường join, tiếp theo là các trường còn lại của dòng trong tập tin thứ nhất, rồi đến các trường còn lại của dòng trong tập tin thứ hai.[1]

Khi không có tùy chọn -t, các trường được phân cách bằng khoảng trắng (dấu cách hoặc tab); nhiều ký tự phân cách liên tiếp được tính là một, và các ký tự phân cách ở đầu dòng bị bỏ qua. Ký tự phân cách trường ở đầu ra mặc định là một dấu cách.[1][7]

Nếu cùng một khóa xuất hiện nhiều lần trong một hoặc cả hai tập tin, lệnh xuất ra mọi tổ hợp giữa các dòng tương ứng, theo thứ tự các dòng được đọc.[1]

Yêu cầu sắp xếp

[sửa | sửa mã nguồn]

Hai tập tin đầu vào phải được sắp xếp theo trường join. Theo POSIX, thứ tự này phải là thứ tự đối chiếu của lệnh sort -b; khi dùng tùy chọn -t, thứ tự phải giống của sort không có -b. Nếu đầu vào không được sắp xếp đúng thì kết quả là không xác định.[1] Trang hướng dẫn của FreeBSD lưu ý rằng khi đó join có thể bỏ sót một số cặp dòng trùng khớp.[7]

Thứ tự đối chiếu phụ thuộc vào locale thông qua biến môi trường LC_COLLATE, vì vậy hai tập tin cần được sắp xếp trong cùng locale mà join sử dụng.[1] Tài liệu GNU khuyên dùng sort -k 1b,1 để chuẩn bị đầu vào khi gọi join không kèm tùy chọn.[6]

Tùy chọn

[sửa | sửa mã nguồn]

Tùy chọn theo POSIX

[sửa | sửa mã nguồn]
Tùy chọnÝ nghĩa[1]
-a nNgoài kết quả mặc định, xuất thêm một dòng cho mỗi dòng không ghép cặp được của tập tin số n (n là 1 hoặc 2). Có thể dùng đồng thời -a 1 và -a 2.
-v nThay cho kết quả mặc định, chỉ xuất những dòng không ghép cặp được của tập tin số n.
-e chuỗiThay các trường đầu ra rỗng trong danh sách chọn bởi -o bằng chuỗi.
-o danh_sáchXác định các trường được xuất ra. Mỗi phần tử có dạng số_tập_tin.số_trường hoặc 0 (trường join), phân cách nhau bằng dấu phẩy hoặc khoảng trắng.
-t ký_tựDùng ký_tự làm dấu phân cách trường cho cả đầu vào và đầu ra. Mọi lần xuất hiện của ký tự này trong dòng đều có nghĩa.
-1 trườngJoin theo trường thứ trường của tập tin 1 (đánh số từ 1).
-2 trườngJoin theo trường thứ trường của tập tin 2 (đánh số từ 1).

Lệnh trả về mã thoát 0 nếu thành công và lớn hơn 0 nếu có lỗi.[1]

Phần mở rộng của GNU

[sửa | sửa mã nguồn]

Phiên bản trong GNU coreutils bổ sung một số tùy chọn ngoài POSIX:[6]

  • -i, --ignore-case: không phân biệt chữ hoa và chữ thường khi so sánh trường.
  • -j trường: tương đương -1 trường -2 trường.
  • --header: coi dòng đầu tiên của mỗi tập tin là dòng tiêu đề và in ra mà không ghép cặp.
  • --check-order và --nocheck-order: bật hoặc tắt việc kiểm tra đầu vào đã được sắp xếp đúng. Theo mặc định, lệnh đưa ra cảnh báo nếu đầu vào chưa sắp xếp và có dòng không ghép được.
  • -z, --zero-terminated: dùng ký tự NUL thay cho ký tự xuống dòng làm dấu kết thúc dòng.
  • -o auto: số trường xuất ra cho mỗi dòng được xác định theo dòng đầu tiên của mỗi tập tin.

Trong ví dụ dưới đây, hai tập tin chứa tên cha và tên mẹ của một số người. Cả hai tập tin đều đã được sắp xếp theo trường join.

Tập tin cha:

george jim
mary john

Tập tin me:

albert martha
george sophie

Lệnh join cha me (không có tùy chọn) trả về:

george jim sophie

Chỉ có "george" xuất hiện ở trường đầu tiên của cả hai tập tin nên chỉ có một dòng kết quả.

Để giữ cả những dòng không ghép cặp được (tương tự full outer join) và điền dấu ? vào trường thiếu:

$ join -a 1 -a 2 -e '?' -o 0,1.2,2.2 cha me
albert ? martha
george jim sophie
mary john ?

Để chỉ liệt kê những dòng của tập tin thứ nhất không có dòng tương ứng trong tập tin thứ hai:

$ join -v 1 cha me
mary john

Khi khóa bị lặp, kết quả là mọi tổ hợp. Với tập tin fa gồm hai dòng a x, a y và tập tin fb gồm hai dòng a p, a q:

$ join fa fb
a x p
a x q
a y p
a y q

Tham khảo

[sửa | sửa mã nguồn]
  1. 1 2 3 4 5 6 7 8 9 10 "join - relational database operator". The Open Group Base Specifications Issue 7, 2018 edition (IEEE Std 1003.1-2017) (bằng tiếng Anh). The Open Group. Truy cập ngày 8 tháng 10 năm 2026.
  2. 1 2 "JOIN(1)". UNIX Programmer's Manual, Seventh Edition (bằng tiếng Anh). Bell Laboratories. Truy cập ngày 8 tháng 10 năm 2026.
  3. 1 2 "join(1)". OpenBSD manual pages (bằng tiếng Anh). Truy cập ngày 8 tháng 10 năm 2026.
  4. 1 2 McIlroy, M. D. (1987). A Research UNIX Reader: Annotated Excerpts from the Programmer's Manual, 1971-1986 (PDF). Computing Science Technical Report 139 (bằng tiếng Anh). AT&T Bell Laboratories.
  5. ↑ "M. Douglas McIlroy: Biography" (bằng tiếng Anh). Bell Laboratories. Truy cập ngày 8 tháng 10 năm 2026.
  6. 1 2 3 "join(1) - Linux manual page". man7.org (bằng tiếng Anh). Truy cập ngày 8 tháng 10 năm 2026.
  7. 1 2 3 "join(1)". FreeBSD Manual Pages (bằng tiếng Anh). Truy cập ngày 8 tháng 10 năm 2026.

Liên kết ngoài

[sửa | sửa mã nguồn]