SSD Nodes Learn 🎉 VPS từ $5.50/tháng
Hướng dẫn Matt ConnorBởi Matt Connor

chmod 755 hay u+x: khác nhau giữa mode số và ký hiệu

Hiểu chmod 755, u+x và u/g/o trên Linux: vì sao chmod số đệ quy có thể phá cả cây thư mục, và khi nào nên dùng X viết hoa.

chmod thay đổi gì

chmod thay đổi các bit quyền trên file hoặc thư mục. Lệnh này chấp nhận các bit quyền theo một trong hai dạng ký hiệu. Dạng số là một số bát phân thay thế toàn bộ các bit quyền cùng lúc. Dạng ký hiệu xác định một nhóm người dùng và một toán tử, rồi chỉ chỉnh sửa các bit được chỉ định. Cả hai dạng cuối cùng đều dùng cùng một system call. Điểm khác nhau là cách xử lý các bit bạn không chỉ định.

Đọc mode và thay đổi mode là hai việc khác nhau. Nếu các chữ cái trong long listing chưa dễ hiểu, trước tiên hãy đọc ý nghĩa của drwxr-xr-x theo từng trường. Hướng dẫn này chỉ thay đổi các bit đó.

Hãy chạy mọi lệnh ở đây bằng user đăng nhập thông thường của bạn. Tài khoản root bỏ qua các kiểm tra này, nên chạy phần minh họa quyền bằng root không chứng minh được điều gì. Nếu bạn vẫn đang làm việc bằng root trên server mới, hãy tạo user thông thường với quyền tối thiểu rồi quay lại.

Thiết lập một sandbox có thể xóa

cd "$(mktemp -d)"
touch notes.txt

mktemp -d tạo một thư mục rỗng bên dưới /tmp và in ra đường dẫn đã tạo, còn phép thay thế lệnh chuyển thẳng đường dẫn đó cho cd. Không có lệnh nào bên dưới tác động đến file bạn cần giữ.

Một lệnh sẽ báo cáo kết quả của từng thay đổi:

stat -c '%a %A %n' notes.txt

%a in mode dưới dạng số bát phân, %A in cùng mode dưới dạng chữ mà long listing sử dụng, còn %n in tên. Trong các khối bên dưới, dòng bắt đầu bằng $ là lệnh bạn nhập, còn dòng bên dưới là kết quả lệnh in ra. Hãy tự chạy các lệnh đó. Output trên máy của bạn phải khớp từng dòng, vì numeric mode không phụ thuộc vào bất kỳ yếu tố nào trong môi trường của bạn.

Dạng số: một chữ số bát phân cho mỗi nhóm

Chữ số thứ nhất thuộc về owner của file. Chữ số thứ hai thuộc về group của file. Chữ số thứ ba thuộc về những người khác. Mỗi chữ số là tổng của các bit, mỗi bit có một giá trị. Bật từng bit một rồi xem stat báo gì.

$ chmod 400 notes.txt
$ stat -c '%a %A %n' notes.txt
400 -r-------- notes.txt
$ chmod 200 notes.txt
$ stat -c '%a %A %n' notes.txt
200 --w------- notes.txt
$ chmod 100 notes.txt
$ stat -c '%a %A %n' notes.txt
100 ---x------ notes.txt

Các chữ cái tương ứng với từng chữ số. Sau ký tự đầu tiên biểu thị loại file, nhóm ba chữ cái đầu tiên là của owner, ba chữ cái tiếp theo là của group, còn ba chữ cái cuối cùng thuộc về những người khác. Cộng các giá trị để kết hợp các bit trong một nhóm.

$ chmod 600 notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txt
$ chmod 700 notes.txt
$ stat -c '%a %A %n' notes.txt
700 -rwx------ notes.txt
$ chmod 750 notes.txt
$ stat -c '%a %A %n' notes.txt
750 -rwxr-x--- notes.txt

Mode dạng số là tuyệt đối. Mỗi lần chạy, lệnh ghi cả 9 bit, nên cả nhóm mà bạn không định thay đổi cũng bị ghi lại.

$ chmod 755 notes.txt
$ stat -c '%a %A %n' notes.txt
755 -rwxr-xr-x notes.txt
$ chmod 600 notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txt

Lệnh thứ hai không nói gì về group hoặc những người khác, nhưng các bit của họ vẫn thay đổi. Đó là đặc điểm của dạng số, và cũng là lý do dạng số không phù hợp cho một chỉnh sửa nhỏ. (chmod cũng xử lý các bit setuid, setgid và sticky, nằm trong chữ số thứ tư phía trước các chữ số này. Đó là một chủ đề riêng, nên hướng dẫn này chỉ tập trung vào 3 chữ số.)

Dạng ký hiệu: class, operator rồi đến các bit

Viết class trước. u là owner, g là group, o là những người khác, còn a là tất cả các class này cùng lúc. Tiếp theo là operator: + thêm các bit, - xóa các bit, còn = đặt class đó đúng bằng các bit bạn liệt kê và xóa các bit còn lại của class đó. Sau đó là các bit, gồm r, w hoặc x.

$ chmod 640 notes.txt
$ stat -c '%a %A %n' notes.txt
640 -rw-r----- notes.txt
$ chmod u+x notes.txt
$ stat -c '%a %A %n' notes.txt
740 -rwxr----- notes.txt
$ chmod g-r notes.txt
$ stat -c '%a %A %n' notes.txt
700 -rwx------ notes.txt
$ chmod o=r notes.txt
$ stat -c '%a %A %n' notes.txt
704 -rwx---r-- notes.txt

Mỗi lệnh chỉ tác động đến một class và giữ nguyên các class khác. Ghép các mệnh đề bằng dấu phẩy, không có khoảng trắng. chmod áp dụng chúng từ trái sang phải.

$ chmod u=rw,go=r notes.txt
$ stat -c '%a %A %n' notes.txt
644 -rw-r--r-- notes.txt
$ chmod go= notes.txt
$ stat -c '%a %A %n' notes.txt
600 -rw------- notes.txt

go= không có gì sau dấu bằng sẽ xóa mọi bit của group và những người khác. Đây là dạng quyền phù hợp với một file chỉ owner mới được đọc, chẳng hạn phần private của một cặp SSH key.

chmod cũng có thể báo lại những gì nó đã thực hiện. Điều này hữu ích trong script khi không có ai theo dõi màn hình.

chmod -v u+x notes.txt
chmod -v u+x notes.txt

-v in một dòng cho mỗi file được truyền vào. Chạy cả hai lệnh rồi so sánh hai dòng trên màn hình: dòng đầu tiên ghi tên file, đồng thời báo mode trước và sau khi thay đổi; dòng thứ hai báo mode được giữ nguyên vì bit cần thêm đã được set. -c chỉ in một dòng khi file thực sự thay đổi, nên phù hợp hơn để ghi vào log.

chmod 755 và u+x: nên dùng dạng nào

Bắt đầu với cùng một file hai lần và so sánh kết quả còn lại của mỗi dạng.

$ chmod 640 notes.txt
$ chmod 755 notes.txt
$ stat -c '%a %A %n' notes.txt
755 -rwxr-xr-x notes.txt
$ chmod 640 notes.txt
$ chmod u+x notes.txt
$ stat -c '%a %A %n' notes.txt
740 -rwxr----- notes.txt

Cả hai lệnh đều thêm quyền thực thi cho owner của file. Chỉ một lệnh giữ nguyên quyền của hai nhóm còn lại. Dùng mode dạng số khi bạn biết chính xác trạng thái cuối cùng cần đạt và muốn bắt buộc trạng thái đó. Đây là lựa chọn phù hợp trong deployment script phải tạo ra cùng một kết quả trên một máy mà bạn chưa từng kiểm tra. Dùng mode dạng ký hiệu khi câu bạn muốn diễn đạt có chứa add hoặc remove, vì dạng số không có cách nào nói rằng cần leave that part alone.

Mode mà một file mới nhận được không đến từ chmod. Nó đến từ umask của process tạo file. Chạy umaskumask -S trong shell của bạn để xem giá trị đang được áp dụng, và lưu ý rằng giá trị này có thể khác giữa các distribution, giữa login shell và systemd service, cũng như giữa các account. umask thiết lập mode cho mọi file mới, nên nó quyết định trạng thái ban đầu trước khi chmod chạy.

Quyền execute trên thư mục có tác dụng gì

Đây là hiểu nhầm gây mất nhiều thời gian nhất. Với file thông thường, quyền execute cho kernel biết có thể chạy file đó. Thư mục không chứa mã lệnh, nên không có gì để chạy trong đó. Trên thư mục, quyền execute có nghĩa là traversal: cho phép phân giải một tên bên trong thư mục đó. Để truy cập dir/file, bạn cần quyền này trên dir. Quyền read là một quyền riêng và cho phép liệt kê các tên mà thư mục chứa. Bạn có thể có một trong hai quyền mà không có quyền còn lại. Điều này sẽ dễ hiểu hơn sau khi bạn trực tiếp thấy nó xảy ra.

$ mkdir vault
$ printf 'hello\n' > vault/secret.txt
$ chmod 600 vault/secret.txt
$ chmod 100 vault
$ echo vault/*
vault/*
$ cat vault/secret.txt
hello

Shell in nguyên mẫu tìm kiếm vì việc mở rộng vault/* yêu cầu đọc thư mục, còn glob không khớp với gì được giữ nguyên dưới dạng văn bản literal thay vì phát sinh lỗi. cat vẫn hoạt động vì bạn tự cung cấp tên và đã được phép traversal. Bây giờ hãy đổi chỗ hai quyền này.

$ chmod 400 vault
$ echo vault/*
vault/secret.txt
$ cat vault/secret.txt
cat: vault/secret.txt: Permission denied

Bạn nhìn thấy tên nhưng không đọc được nội dung. Read cung cấp danh sách. Execute cung cấp đường dẫn để truy cập vào bên trong. Hầu hết thư mục bạn sử dụng đều cần cả hai quyền.

$ chmod 500 vault
$ cat vault/secret.txt
hello

Vì sao dùng chmod -R với mode dạng số làm hỏng cả cây thư mục

-R đi qua toàn bộ cây thư mục và áp dụng mode bạn chỉ định cho mọi thứ nó gặp. Thư mục và file dữ liệu cần các bit khác nhau, nên một số tuyệt đối duy nhất không thể đúng cho cả hai. Hãy tạo một cây thư mục nhỏ và xem lỗi xảy ra.

$ mkdir -p site/css
$ touch site/index.html site/css/main.css
$ printf '#!/bin/bash\necho hi\n' > site/deploy.sh
$ chmod 755 site site/css site/deploy.sh
$ chmod 644 site/index.html site/css/main.css
$ stat -c '%a %A %n' site site/css site/index.html site/css/main.css site/deploy.sh
755 drwxr-xr-x site
755 drwxr-xr-x site/css
644 -rw-r--r-- site/index.html
644 -rw-r--r-- site/css/main.css
755 -rwxr-xr-x site/deploy.sh

Đó là cấu trúc phù hợp với một thư mục chứa các file tĩnh. Đây là lỗi đệ quy đầu tiên.

$ chmod -R 755 site
$ stat -c '%a %A %n' site/index.html site/css/main.css
755 -rwxr-xr-x site/index.html
755 -rwxr-xr-x site/css/main.css

Không có gì bị hỏng, và đó mới là vấn đề. Lỗi này không tạo ra dấu hiệu rõ ràng, nên có thể tồn tại nhiều năm trong các hướng dẫn được sao chép. Hai file dữ liệu giờ được đánh dấu là chương trình. Git lưu cả execute bit, nên commit tiếp theo của bạn sẽ mang thay đổi này đến mọi người clone repository, còn rsynctar sẽ mang nó đến mọi máy mà bạn copy cây thư mục này sang.

Lỗi đệ quy thứ hai dễ nhận thấy hơn. Nếu áp dụng mode không có execute bit cho một thư mục, thư mục đó sẽ bị khóa.

$ chmod 644 site
$ stat -c '%a %A %n' site
644 drw-r--r-- site
$ echo site/*
site/css site/deploy.sh site/index.html
$ cd site
bash: cd: site: Permission denied
$ cat site/index.html
cat: site/index.html: Permission denied

Tên file vẫn được liệt kê vì read bit vẫn còn, nhưng mọi path đi qua thư mục đều bị khóa vì execute bit đã bị loại bỏ. chmod -R 644 site sẽ làm điều đó với mọi thư mục trong cây chỉ bằng một command. Trạng thái sau đó cũng không phải lúc nào đồng nhất, vì chmod phải đi qua chính các thư mục mà nó đang loại bỏ quyền traversal, nên hãy dùng find site -type d -exec stat -c '%a %n' {} + để kiểm tra kết quả thực tế thay vì tự giả định. Khôi phục thư mục này trước khi tiếp tục.

$ chmod 755 site
$ chmod 644 site/index.html site/css/main.css
$ stat -c '%a %A %n' site site/index.html
755 drwxr-xr-x site
644 -rw-r--r-- site/index.html

chmod đệ quy không có thao tác hoàn tác. chmod không lưu lại các mode mà nó đã thay thế, nên việc sửa chữa phụ thuộc vào bạn: phải dựng lại mode dựa trên những gì bạn nghĩ chúng từng có. Đó cũng là công việc chậm và không chắc chắn như khôi phục file sau khi vô tình chạy rm -rf, và bài học cũng giống nhau: kiểm tra target của command đệ quy trước khi nhấn Enter.

Chữ X viết hoa: đặt quyền thực thi cho thư mục, không phải mọi file

Symbolic mode chấp nhận cả Xx. X chỉ đặt bit thực thi ở nơi phù hợp: trên thư mục hoặc trên file thông thường đã có bit thực thi cho một class nào đó. Quy tắc này đúng với điều bạn muốn -R thực hiện.

$ chmod -R u=rwX,go=rX site
$ stat -c '%a %A %n' site site/css site/index.html site/css/main.css site/deploy.sh
755 drwxr-xr-x site
755 drwxr-xr-x site/css
644 -rw-r--r-- site/index.html
644 -rw-r--r-- site/css/main.css
755 -rwxr-xr-x site/deploy.sh

Chỉ một lệnh, các thư mục vẫn có thể truy cập được còn các file dữ liệu không bị thay đổi. Script vẫn giữ bit thực thi vì trước đó nó đã có bit này. Đây là nửa còn lại của quy tắc X. X đọc mode hiện tại của file, nên file đã mất toàn bộ bit thực thi sẽ không thể lấy lại bit đó bằng lệnh này.

$ chmod 644 site/deploy.sh
$ chmod -R u=rwX,go=rX site
$ stat -c '%a %A %n' site/deploy.sh
644 -rw-r--r-- site/deploy.sh
$ site/deploy.sh
bash: site/deploy.sh: Permission denied
$ chmod u+x site/deploy.sh
$ stat -c '%a %A %n' site/deploy.sh
744 -rwxr--r-- site/deploy.sh
$ site/deploy.sh
hi

Quy tắc tương tự cũng hoạt động theo chiều ngược lại. X sẽ mở rộng bit thực thi mà file đã có sang một class khác:

$ chmod go+X site/deploy.sh
$ stat -c '%a %A %n' site/deploy.sh
755 -rwxr-xr-x site/deploy.sh

Vì vậy, chữ x viết thường dùng cho một file cụ thể mà bạn muốn cho phép chạy, còn X dùng để quét toàn bộ cây thư mục. Khi cần đặt mode chính xác theo từng loại đối tượng thay vì áp dụng quy tắc dựa trên mode hiện tại, hãy tách quá trình duyệt bằng find.

find site -type d -exec chmod 755 {} +
find site -type f -exec chmod 644 {} +
chmod u+x site/deploy.sh

-type d chọn các thư mục còn -type f chọn các file thông thường, nên mỗi loại nhận được mode phù hợp. -exec ... + gộp nhiều path vào một lần gọi chmod thay vì khởi động một process cho từng file. Điều này quan trọng với cây thư mục có hàng nghìn mục. Script được khôi phục bit thực thi trên một dòng riêng, theo chủ ý.

Kiểm tra kết quả trước khi rời đi

Hai lệnh này tìm ra những lỗi quan trọng sau mọi thay đổi đệ quy. Lệnh đầu tiên liệt kê các thư mục mà bạn không còn có thể truy cập.

find . -type d ! -perm -u+x

Lệnh thứ hai liệt kê các tệp mà mọi tài khoản trên máy đều có thể chỉnh sửa.

find . -type f -perm -o+w

Trong -perm -o+w, - ở đầu có nghĩa là ít nhất phải có các bit này, nên lệnh khớp với tệp mà class o của tệp có write bit, bất kể các thiết lập khác là gì. Kết quả đúng là cả hai lệnh đều không in gì. Hãy chạy cả hai từ thư mục gốc của mọi cây thư mục mà bạn vừa thay đổi bằng -R, rồi chạy stat -c '%a %A %n' trên một số ít đường dẫn mà bạn thực sự định thay đổi, để xác nhận mode bạn nghĩ mình đã đặt đúng là mode kernel đang lưu.

FAQ

Sự khác nhau giữa chmod 755 và chmod u+x là gì?

Mode dạng số là tuyệt đối. Nó ghi lại mọi bit quyền trên file, nên cả những class bạn không định thay đổi cũng bị ghi đè. Mode dạng symbol là một phép chỉnh sửa. u+x thêm một bit cho owner và giữ nguyên mọi bit khác. Dùng dạng số khi bạn biết chính xác trạng thái cuối muốn đặt cho file. Dùng dạng symbol khi bạn chỉ muốn thêm hoặc xóa một quyền. Chạy stat -c '%a %A %n' <file> trước và sau mỗi lệnh để thấy khác biệt trong output.

Vì sao chmod -R 755 trên một thư mục chứa các file web là ý tưởng tồi?

-R áp dụng cùng một mode tuyệt đối cho thư mục và regular file, trong khi hai loại này cần các bit khác nhau. Thư mục cần bit execute để có thể traverse. Các file dữ liệu như HTML và CSS không cần bit này. Đánh dấu chúng là executable sẽ tạo ra một thay đổi được git ghi nhận trong commit tiếp theo và rsync sao chép sang máy tiếp theo. Dùng chmod -R u=rwX,go=rX <dir> để chỉ đặt bit execute cho các thư mục, hoặc dùng find với -type d-type f để đặt mode riêng cho từng loại.

Bit execute trên một thư mục có tác dụng gì?

Nó cho phép traverse, không phải execution. Bên trong thư mục không có gì để chạy. Bit execute cho phép resolve một tên bên trong thư mục, vì vậy bạn cần bit này trên mọi thư mục dọc theo path trước khi có thể mở file ở cuối path. Bit read là quyền riêng và cho phép list tên các mục. Bạn có thể có một bit mà không có bit kia: chỉ với execute, bạn có thể mở một file khi đã biết tên, nhưng shell không thể expand glob trong thư mục đó; chỉ với read, bạn có thể thấy các tên nhưng mọi lần thử mở một mục đều fail.

Khi nào nên dùng X viết hoa thay vì x viết thường?

Dùng X khi lệnh có tính recursive. X đặt bit execute trên các thư mục và trên regular file chỉ khi một bit execute đã được đặt sẵn. Vì vậy, một lần chạy có thể làm cho cả cây thư mục traverse được mà không biến các file dữ liệu thành chương trình. Dùng x viết thường x khi bạn chỉ định một file và muốn áp dụng trực tiếp cho file đó. Có một giới hạn cần nhớ: X không thể khôi phục bit execute đã bị xóa hoàn toàn trên một file, vì không còn bit nào để làm điều kiện match. Khôi phục bit đó bằng chmod u+x <file>.

chmod có thay đổi người sở hữu file không?

Không. chmod chỉ thay đổi các bit quyền. Quyền sở hữu thuộc về chown đối với user và chgrp đối với group; chuyển file cho user khác cần root. Điều này quan trọng vì các bit được đối chiếu với owner và group được ghi trên file, không phải với người đã ghi file gần nhất. Chạy stat -c '%U %G %a %n' <file> để xem owner, group và mode cùng lúc trước khi quyết định cần lệnh nào trong 3 lệnh.