SSD Nodes Learn 🎉 VPS เริ่ม $5.50/เดือน
คู่มือ Matt Connorโดย Matt Connor

ความแตกต่าง chmod 755 กับ u+x และการใช้โหมดสัญลักษณ์

เรียนรู้การใช้คำสั่ง chmod ทั้งรูปแบบตัวเลขและสัญลักษณ์ เข้าใจเหตุผลว่าทำไมการใช้เลขฐานแปดแบบ recursive ถึงทำให้สิทธิ์ไฟล์ผิดพลาด และวิธีใช้ตัวเลือก X เพื่อแก้ไขปัญหาอย่างถูกต้อง

การเปลี่ยนแปลงด้วย chmod

chmod คำสั่ง chmod ใช้สำหรับเปลี่ยนบิตสิทธิ์การเข้าถึงไฟล์หรือไดเรกทอรี โดยรองรับการระบุสิทธิ์ผ่านรูปแบบหลัก 2 แบบ รูปแบบตัวเลข (numeric) คือเลขฐานแปดที่ใช้แทนที่บิตสิทธิ์ทั้งหมดในคราวเดียว ส่วนรูปแบบสัญลักษณ์ (symbolic) จะระบุกลุ่มผู้ใช้และตัวดำเนินการเพื่อแก้ไขเฉพาะบิตที่คุณกำหนดเท่านั้น ทั้งสองรูปแบบจะส่งผลลัพธ์สุดท้ายไปยัง system call เดียวกัน ความแตกต่างอยู่ที่สิ่งที่เกิดขึ้นกับบิตที่คุณไม่ได้ระบุถึง

การอ่านค่าโหมดและการเปลี่ยนโหมดเป็นงานที่แตกต่างกัน หากคุณยังไม่เข้าใจความหมายของตัวอักษรในการแสดงรายการไฟล์แบบยาว ให้ศึกษา ความหมายของ drwxr-xr-x ในแต่ละฟิลด์ ก่อน คู่มือนี้จะเน้นไปที่การเปลี่ยนแปลงสิทธิ์เท่านั้น

ให้รันคำสั่งทั้งหมดในที่นี้ด้วยบัญชีผู้ใช้ปกติของคุณ บัญชี root สามารถข้ามการตรวจสอบสิทธิ์เหล่านี้ได้ ดังนั้นการสาธิตเรื่องสิทธิ์โดยใช้ root จึงไม่สามารถพิสูจน์ผลลัพธ์ที่ถูกต้องได้ หากคุณยังคงใช้งานในฐานะ root บนเซิร์ฟเวอร์ใหม่ ให้สร้าง ผู้ใช้ปกติที่มีสิทธิ์น้อยที่สุด แล้วจึงกลับมาดำเนินการต่อ

การตั้งค่าแซนด์บ็อกซ์แบบใช้แล้วทิ้ง

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

mktemp -d จะสร้างไดเรกทอรีว่างไว้ภายใต้ /tmp และแสดงพาธที่สร้างขึ้นมา จากนั้น การแทนที่คำสั่ง จะส่งพาธนั้นไปยัง cd โดยตรง สิ่งที่อยู่ด้านล่างนี้จะไม่ส่งผลกระทบต่อไฟล์ที่คุณใช้งานจริง

คำสั่งเดียวสามารถรายงานผลลัพธ์ของการเปลี่ยนแปลงทุกอย่างได้:

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

%a จะแสดงโหมดในรูปแบบเลขฐานแปด %A จะแสดงโหมดเดียวกันในรูปแบบตัวอักษรที่ใช้ในรายการแบบยาว และ %n จะแสดงชื่อไฟล์ ในบล็อกถัดไป บรรทัดที่ขึ้นต้นด้วย $ คือสิ่งที่คุณต้องพิมพ์ และบรรทัดด้านล่างคือสิ่งที่คำสั่งแสดงผลออกมา คุณสามารถลองรันคำสั่งเหล่านี้ด้วยตัวเอง ผลลัพธ์บนเครื่องของคุณควรจะตรงกันบรรทัดต่อบรรทัด เนื่องจากโหมดที่เป็นตัวเลขไม่ได้ขึ้นอยู่กับสภาพแวดล้อมใดๆ ในเครื่องของคุณ

รูปแบบตัวเลข: หนึ่งเลขฐานแปดต่อหนึ่งกลุ่มสิทธิ์

เลขหลักแรกเป็นของเจ้าของไฟล์ เลขหลักที่สองเป็นของกลุ่มผู้ใช้ของไฟล์ และเลขหลักที่สามเป็นของผู้อื่น ทั้งหมดนี้ แต่ละหลักคือผลรวมของค่าบิต โดยแต่ละบิตมีค่าเฉพาะตัว ให้ลองตั้งค่าทีละบิตแล้วสังเกตผลลัพธ์ที่ stat รายงาน

$ 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

ตัวอักษรจะเรียงตรงกับตัวเลข หลังจากอักขระระบุประเภทไฟล์ในตำแหน่งแรก กลุ่มตัวอักษรสามตัวแรกจะเป็นสิทธิ์ของเจ้าของ กลุ่มถัดมาสามตัวเป็นของกลุ่มผู้ใช้ และสามตัวสุดท้ายเป็นของผู้อื่นทั้งหมด ให้บวกค่าต่างๆ เพื่อรวมบิตภายในกลุ่มเดียวกัน

$ 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

โหมดตัวเลขเป็นการกำหนดค่าแบบสัมบูรณ์ (absolute) ซึ่งจะเขียนบิตทั้งเก้าบิตทุกครั้งที่รันคำสั่ง ดังนั้นกลุ่มสิทธิ์ที่คุณอาจไม่ได้ตั้งใจจะแก้ไขก็จะถูกเขียนทับไปด้วย

$ 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

คำสั่งที่สองไม่ได้ระบุถึงกลุ่มผู้ใช้หรือผู้อื่นเลย แต่บิตของกลุ่มเหล่านั้นก็ถูกเปลี่ยนแปลงไป นี่คือลักษณะเฉพาะของรูปแบบตัวเลข และเป็นเหตุผลว่าทำไมรูปแบบตัวเลขจึงไม่ใช่เครื่องมือที่เหมาะสมสำหรับการแก้ไขสิทธิ์เพียงเล็กน้อย (chmod ยังสามารถจัดการกับบิต setuid, setgid และ sticky ซึ่งอยู่ในหลักที่สี่นำหน้าหลักทั้งสามนี้ได้อีกด้วย แต่เรื่องนั้นเป็นหัวข้อแยกต่างหาก และคู่มือนี้จะกล่าวถึงเพียงสามหลักเท่านั้น)

รูปแบบสัญลักษณ์: คลาส, ตัวดำเนินการ, และบิต

ให้เขียนคลาสก่อน u คือเจ้าของ g คือกลุ่ม o คือผู้อื่นทั้งหมด และ a คือทั้งหมดพร้อมกัน จากนั้นตามด้วยตัวดำเนินการ + ใช้เพิ่มบิต - ใช้ลบบิต และ = ใช้กำหนดบิตให้คลาสนั้นตามรายการที่ระบุและล้างบิตที่เหลือออก จากนั้นตามด้วยตัวบิตเอง ได้แก่ r, w หรือ 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

คำสั่งแต่ละคำสั่งจะส่งผลต่อคลาสเดียวและคงค่าคลาสอื่นไว้ตามเดิม คุณสามารถรวมเงื่อนไขเข้าด้วยกันโดยใช้เครื่องหมายจุลภาคคั่นโดยไม่ต้องเว้นวรรค และ chmod จะประมวลผลจากซ้ายไปขวา

$ 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= โดยไม่มีค่าตามหลังเครื่องหมายเท่ากับจะเป็นการลบบิตทั้งหมดออกจากกลุ่มและผู้อื่น นี่คือรูปแบบที่คุณต้องการสำหรับไฟล์ที่อนุญาตให้เฉพาะเจ้าของอ่านได้เท่านั้น เช่น ส่วนที่เป็น private ของ SSH key pair

chmod สามารถรายงานการทำงานของตัวเองได้ ซึ่งมีความสำคัญเมื่อรันภายในสคริปต์ที่ไม่มีใครเฝ้าดูหน้าจอ

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

-v จะแสดงบรรทัดสำหรับทุกไฟล์ที่ได้รับคำสั่ง ให้ลองรันทั้งสองคำสั่งแล้วเปรียบเทียบสองบรรทัดบนหน้าจอของคุณ บรรทัดแรกจะระบุชื่อไฟล์และรายงานโหมดก่อนและหลังการเปลี่ยนแปลง ส่วนบรรทัดที่สองจะรายงานว่าโหมดคงเดิมเนื่องจากบิตที่สั่งให้เพิ่มนั้นถูกตั้งค่าไว้ก่อนแล้ว -c จะแสดงบรรทัดเฉพาะเมื่อไฟล์มีการเปลี่ยนแปลงจริงเท่านั้น จึงเป็นตัวเลือกที่ดีกว่าสำหรับการเก็บลงใน log

chmod 755 เทียบกับ u+x: ควรใช้รูปแบบใด

เริ่มต้นจากไฟล์เดียวกันสองครั้งแล้วเปรียบเทียบผลลัพธ์ที่แต่ละรูปแบบทิ้งไว้

$ 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

คำสั่งทั้งสองทำให้ไฟล์สามารถเรียกใช้งานได้ (executable) สำหรับเจ้าของไฟล์ มีเพียงรูปแบบเดียวเท่านั้นที่คงสิทธิ์ของอีกสองกลุ่มไว้ตามเดิม ให้ใช้โหมดตัวเลข (numeric mode) เมื่อคุณทราบสถานะปลายทางที่ต้องการอย่างชัดเจนและต้องการบังคับใช้ ซึ่งเป็นกรณีที่ถูกต้องสำหรับสคริปต์การติดตั้ง (deployment script) ที่ต้องให้ผลลัพธ์เหมือนกันบนเครื่องที่คุณไม่เคยเห็นมาก่อน ให้ใช้โหมดสัญลักษณ์ (symbolic mode) เมื่อประโยคในหัวของคุณมีคำว่า เพิ่ม หรือ ลบ เนื่องจากรูปแบบตัวเลขไม่มีวิธีระบุว่า ให้คงส่วนนั้นไว้ตามเดิม

โหมดเริ่มต้นของไฟล์ ใหม่ ไม่ได้มาจาก chmod แต่มาจาก umask ของกระบวนการที่สร้างไฟล์นั้นขึ้นมา ให้รัน umask และ umask -S ในเชลล์ของคุณเพื่อดูค่าที่ใช้งานอยู่ และควรคาดการณ์ไว้ว่าค่านี้จะแตกต่างกันไปในแต่ละ distribution, ระหว่าง login shell ของคุณกับ systemd service และระหว่างบัญชีผู้ใช้หนึ่งกับอีกบัญชีหนึ่ง umask เป็นตัวกำหนดโหมดของไฟล์ใหม่ทุกไฟล์ ดังนั้นมันจึงเป็นตัวตัดสินว่าคุณเริ่มต้นจากจุดใดก่อนที่ chmod จะทำงาน

หน้าที่ของ execute bit บนไดเรกทอรี

นี่คือความเข้าใจผิดที่ทำให้เสียเวลามากที่สุด สำหรับไฟล์ทั่วไป execute bit หมายถึง kernel สามารถรันไฟล์นั้นได้ แต่ไดเรกทอรีไม่มีชุดคำสั่งใดๆ จึงไม่มีอะไรให้รัน สำหรับไดเรกทอรี execute bit หมายถึงการเข้าถึง (traversal): คือสิทธิ์ในการระบุชื่อไฟล์ที่อยู่ภายในไดเรกทอรีนั้น การจะเข้าถึง dir/file คุณจำเป็นต้องมีสิทธิ์นี้บน dir ส่วน read bit เป็นสิทธิ์แยกต่างหาก ซึ่งอนุญาตให้แสดงรายการชื่อไฟล์ที่ไดเรกทอรีนั้นเก็บไว้ คุณสามารถมีสิทธิ์อย่างใดอย่างหนึ่งโดยไม่มีอีกอย่างได้ ซึ่งเป็นเรื่องที่เข้าใจได้ง่ายขึ้นเมื่อคุณได้เห็นผลลัพธ์ด้วยตนเอง

$ 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 แสดงรูปแบบกลับมาโดยไม่มีการเปลี่ยนแปลง เพราะการขยาย vault/* หมายถึงการอ่านไดเรกทอรี และ glob ที่ไม่ตรงกับไฟล์ใดเลย จะถูกส่งผ่านไปเป็นข้อความตัวอักษรแทนที่จะแจ้งข้อผิดพลาด cat ยังคงทำงานได้เพราะคุณระบุชื่อไฟล์ด้วยตนเองและได้รับอนุญาตให้เข้าถึงไดเรกทอรี ตอนนี้ลองสลับสิทธิ์ทั้งสองนี้ดู

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

ชื่อไฟล์ต่างๆ จะมองเห็นได้แต่ไม่สามารถเข้าถึงเนื้อหาภายในได้ สิทธิ์ read ช่วยให้คุณเห็นรายการไฟล์ ส่วนสิทธิ์ execute ช่วยให้คุณเข้าไปข้างในได้ ไดเรกทอรีเกือบทุกแห่งที่คุณใช้งานต้องการสิทธิ์ทั้งสองอย่างนี้

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

เหตุใดการใช้ chmod -R พร้อมโหมดตัวเลขจึงสร้างความเสียหายต่อโครงสร้างไฟล์

-R จะไล่ตรวจสอบทั้งโครงสร้างไดเรกทอรีและปรับใช้โหมดที่คุณกำหนดกับทุกสิ่งที่พบ ไดเรกทอรีและไฟล์ข้อมูลต้องการบิตสิทธิ์ที่แตกต่างกัน ดังนั้นตัวเลขชุดเดียวจึงไม่สามารถถูกต้องสำหรับทั้งสองอย่างได้ ลองสร้างโครงสร้างไฟล์ขนาดเล็กแล้วสังเกตความผิดพลาดที่เกิดขึ้น

$ 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

นั่นคือรูปแบบสิทธิ์ที่ไดเรกทอรีของไฟล์แบบ static ต้องการ ต่อไปนี้คือความผิดพลาดแบบ recursive ครั้งแรก

$ 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

ไม่มีสิ่งใดเสียหาย และนั่นคือปัญหา ความผิดพลาดนี้เกิดขึ้นโดยไม่มีการแจ้งเตือน จึงถูกส่งต่อในคำแนะนำที่คัดลอกกันมานานหลายปี ไฟล์ข้อมูลสองไฟล์ถูกระบุว่าเป็นโปรแกรม Git จะจัดเก็บ execute bit ไว้ ดังนั้นการ commit ครั้งถัดไปของคุณจะนำการเปลี่ยนแปลงนี้ไปสู่ทุกคนที่ clone repository และ rsync กับ tar จะนำค่านี้ติดตัวไปทุกเครื่องที่คุณคัดลอกโครงสร้างไฟล์นี้ไป

ความผิดพลาดแบบ recursive ครั้งที่สองนั้นส่งผลกระทบชัดเจน หากคุณกำหนดโหมดที่ไม่มี execute bit ให้กับไดเรกทอรี ไดเรกทอรีนั้นจะถูกปิดกั้น

$ 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

ชื่อไฟล์ยังคงแสดงอยู่เนื่องจาก read bit ยังคงอยู่ แต่ทุกเส้นทางผ่านไดเรกทอรีจะถูกปิดลงเพราะ execute bit ถูกลบออกไป chmod -R 644 site จะกระทำการดังกล่าวกับทุกไดเรกทอรีในโครงสร้างไฟล์ด้วยคำสั่งเดียว สิ่งที่คุณพบหลังจากนั้นอาจไม่สม่ำเสมอเสมอไป เนื่องจาก chmod ต้องไล่ผ่านไดเรกทอรีเดียวกับที่มันกำลังลบสิทธิ์การเข้าถึงออกไป ดังนั้นให้ตรวจสอบผลลัพธ์ที่เกิดขึ้นจริงด้วย find site -type d -exec stat -c '%a %n' {} + แทนการคาดเดา และแก้ไขให้กลับเป็นค่าเดิมก่อนดำเนินการต่อ

$ 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 แบบ recursive ไม่สามารถย้อนกลับได้ chmod ไม่ได้บันทึกค่าเดิมที่ถูกแทนที่ไว้ ดังนั้นการแก้ไขจึงเป็นหน้าที่ของคุณในการกู้คืนโหมดกลับไปตามที่คุณเชื่อว่าเคยเป็น งานนี้เป็นงานที่ช้าและไม่แน่นอนเช่นเดียวกับ การกู้คืนไฟล์หลังจากเผลอใช้ rm -rf และบทเรียนก็คือสิ่งเดียวกัน: ตรวจสอบเป้าหมายของคำสั่งแบบ recursive ก่อนกด Enter ทุกครั้ง

การใช้ X ตัวพิมพ์ใหญ่: การกำหนดสิทธิ์ execute บนไดเรกทอรีโดยไม่กระทบไฟล์ทั่วไป

โหมดสัญลักษณ์รองรับ X เช่นเดียวกับ x โดย X จะกำหนดบิต execute เฉพาะในกรณีที่เหมาะสมเท่านั้น ได้แก่ บนไดเรกทอรี หรือบนไฟล์ทั่วไปที่มีบิต execute สำหรับคลาสใดคลาสหนึ่งอยู่ก่อนแล้ว กฎนี้เป็นกฎเดียวกับที่คุณต้องการให้ -R ปฏิบัติตาม

$ 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

เพียงคำสั่งเดียว ไดเรกทอรียังคงสามารถเข้าถึงได้ (traversable) ในขณะที่ไฟล์ข้อมูลไม่ถูกเปลี่ยนแปลง สคริปต์ยังคงรักษาบิต execute ไว้ได้เพราะมีบิตดังกล่าวอยู่ก่อนแล้ว ซึ่งเป็นส่วนที่สองของกฎ X เนื่องจาก X จะอ่านค่าโหมดที่ไฟล์มีอยู่ในปัจจุบัน ดังนั้นไฟล์ที่สูญเสียบิต execute ไปทั้งหมดแล้วจะไม่สามารถกู้คืนกลับมาได้ด้วยวิธีนี้

$ 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

กฎเดียวกันนี้สามารถใช้ในทางกลับกันได้ โดย X จะขยายบิต execute ที่ไฟล์มีอยู่แล้วไปยังคลาสอื่น:

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

ดังนั้น x ตัวพิมพ์เล็กจึงใช้สำหรับไฟล์ที่ระบุเจาะจงเพื่อให้รันได้ ส่วน X ใช้สำหรับการกวาดสิทธิ์ทั่วทั้งโครงสร้างไดเรกทอรี หากคุณต้องการกำหนดโหมดที่แน่นอนสำหรับไฟล์แต่ละประเภทแทนที่จะใช้กฎที่อ้างอิงจากโหมดปัจจุบัน ให้แยกการทำงานด้วย find แทน

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

-type d ใช้เลือกไดเรกทอรี และ -type f ใช้เลือกไฟล์ทั่วไป เพื่อให้แต่ละประเภทได้รับโหมดที่ควรจะเป็น ส่วน -exec ... + จะรวมหลายพาธเข้าด้วยกันในการเรียกใช้ chmod เพียงครั้งเดียว แทนที่จะเริ่มกระบวนการใหม่ต่อหนึ่งไฟล์ ซึ่งมีความสำคัญมากเมื่อต้องจัดการกับโครงสร้างที่มีไฟล์จำนวนหลายพันรายการ สำหรับสคริปต์นั้นจะได้รับบิต execute คืนมาในบรรทัดแยกต่างหากโดยเจตนา

ตรวจสอบผลลัพธ์ก่อนเสร็จสิ้นการทำงาน

คำสั่งสองคำสั่งต่อไปนี้จะช่วยค้นหาข้อผิดพลาดที่สำคัญหลังจากการเปลี่ยนแปลงแบบ recursive คำสั่งแรกจะแสดงรายการไดเรกทอรีที่คุณไม่สามารถเข้าถึงได้อีกต่อไป

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

คำสั่งที่สองจะแสดงรายการไฟล์ที่บัญชีผู้ใช้ใดก็ตามบนเครื่องสามารถแก้ไขได้

find . -type f -perm -o+w

ใน -perm -o+w เครื่องหมาย - ที่อยู่ด้านหน้าหมายถึง บิตเหล่านี้เป็นอย่างน้อย ดังนั้นคำสั่งนี้จะจับคู่กับไฟล์ที่คลาส o มีการตั้งค่า write bit ไว้ไม่ว่าจะมีบิตอื่นใดถูกตั้งค่าไว้อีกหรือไม่ ผลลัพธ์ที่คุณต้องการคือการที่คำสั่งทั้งสองไม่แสดงผลลัพธ์ใดๆ ออกมา ให้รันคำสั่งทั้งสองจากระดับบนสุดของโครงสร้างไดเรกทอรีที่คุณเพิ่งเปลี่ยนแปลงด้วย -R และรัน stat -c '%a %A %n' กับพาธจำนวนหนึ่งที่คุณตั้งใจจะเปลี่ยนแปลง เพื่อยืนยันว่าโหมดที่คุณเชื่อว่าได้ตั้งค่าไว้นั้นเป็นโหมดที่ kernel ใช้งานอยู่จริง

FAQ

chmod 755 กับ chmod u+x ต่างกันอย่างไร

โหมดตัวเลขเป็นการกำหนดค่าแบบสัมบูรณ์ (absolute) ซึ่งจะเขียนทับบิตสิทธิ์ทั้งหมดของไฟล์ ทำให้คลาสที่คุณไม่ได้ระบุไว้ถูกเขียนทับไปด้วย ส่วนโหมดสัญลักษณ์เป็นการแก้ไขค่า u+x จะเพิ่มเพียงหนึ่งบิตให้กับเจ้าของไฟล์โดยไม่กระทบต่อบิตอื่น ๆ ให้ใช้โหมดตัวเลขเมื่อคุณต้องการกำหนดสถานะสุดท้ายของไฟล์อย่างชัดเจน และใช้โหมดสัญลักษณ์เมื่อต้องการเพิ่มหรือลบสิทธิ์เพียงอย่างเดียว ให้รัน stat -c '%a %A %n' <file> ก่อนและหลังการใช้คำสั่งทั้งสองรูปแบบเพื่อดูความแตกต่างที่เกิดขึ้นในผลลัพธ์

ทำไมการใช้ chmod -R 755 กับไดเรกทอรีไฟล์เว็บจึงเป็นความคิดที่ไม่ดี

เพราะ -R จะกำหนดโหมดสัมบูรณ์เดียวกันให้กับทั้งไดเรกทอรีและไฟล์ทั่วไป ซึ่งทั้งสองอย่างนี้ต้องการบิตที่แตกต่างกัน ไดเรกทอรีจำเป็นต้องมี execute bit เพื่อให้สามารถเข้าถึง (traverse) ได้ แต่ไฟล์ข้อมูลอย่าง HTML หรือ CSS ไม่จำเป็นต้องมี และการทำเครื่องหมายให้ไฟล์เหล่านี้เป็นไฟล์ที่รันได้ (executable) จะทำให้ git บันทึกการเปลี่ยนแปลงนี้ในการ commit ครั้งถัดไป และ rsync จะคัดลอกค่านี้ไปยังเครื่องปลายทางด้วย ให้ใช้ chmod -R u=rwX,go=rX <dir> เพื่อกำหนด execute bit ให้กับไดเรกทอรีเท่านั้น หรือใช้ find ร่วมกับ -type d และ -type f เพื่อกำหนดโหมดที่เหมาะสมแยกกันสำหรับไฟล์แต่ละประเภท

execute bit บนไดเรกทอรีทำหน้าที่อะไร

มันให้สิทธิ์ในการเข้าถึง (traversal) ไม่ใช่การรันโปรแกรม ภายในไดเรกทอรีไม่มีสิ่งใดให้รัน execute bit คือสิทธิ์ในการระบุชื่อไฟล์ที่อยู่ภายในไดเรกทอรีนั้น ดังนั้นคุณจึงจำเป็นต้องมีสิทธิ์นี้ในทุกไดเรกทอรีตลอดเส้นทาง (path) ก่อนที่จะเปิดไฟล์ที่ปลายทางได้ ส่วน read bit เป็นสิทธิ์แยกต่างหากที่ให้สิทธิ์ในการแสดงรายการชื่อไฟล์ คุณสามารถมีสิทธิ์อย่างใดอย่างหนึ่งโดยไม่มีอีกอย่างได้ เช่น หากมีเฉพาะ execute bit คุณจะสามารถเปิดไฟล์ที่ทราบชื่ออยู่แล้วได้แม้ shell จะไม่สามารถขยาย glob ในไดเรกทอรีนั้นได้ หรือหากมีเฉพาะ read bit คุณจะเห็นชื่อไฟล์แต่จะล้มเหลวทุกครั้งที่พยายามเปิดไฟล์เหล่านั้น

เมื่อใดควรใช้ X ตัวพิมพ์ใหญ่แทน x ตัวพิมพ์เล็ก

ให้ใช้ X เมื่อคำสั่งมีการทำงานแบบ recursive X จะตั้งค่า execute bit ให้กับไดเรกทอรี และตั้งค่าให้กับไฟล์ทั่วไปเฉพาะในกรณีที่ไฟล์นั้นมี execute bit ตั้งไว้อยู่แล้ว การทำเช่นนี้จะทำให้โครงสร้างไดเรกทอรีสามารถเข้าถึงได้ในการรันคำสั่งเพียงครั้งเดียวโดยไม่เปลี่ยนไฟล์ข้อมูลให้กลายเป็นโปรแกรม ให้ใช้ x ตัวพิมพ์เล็กเมื่อคุณระบุไฟล์เพียงไฟล์เดียวและต้องการจัดการไฟล์นั้นโดยเฉพาะ มีข้อจำกัดหนึ่งที่ควรจำไว้คือ X ไม่สามารถกู้คืน execute bit ที่ถูกลบออกไปจากไฟล์ทั้งหมดได้ เพราะไม่มีบิตเหลือให้ตรวจสอบเงื่อนไข ให้ใช้ chmod u+x <file> เพื่อกำหนดค่ากลับคืนในกรณีดังกล่าว

chmod เปลี่ยนเจ้าของไฟล์หรือไม่

ไม่เปลี่ยน chmod เปลี่ยนเฉพาะบิตสิทธิ์เท่านั้น การเป็นเจ้าของไฟล์ถูกกำหนดโดย chown สำหรับผู้ใช้ และ chgrp สำหรับกลุ่ม การเปลี่ยนเจ้าของไฟล์ไปยังผู้ใช้อื่นจำเป็นต้องใช้สิทธิ์ root เรื่องนี้มีความสำคัญเพราะบิตสิทธิ์จะถูกตรวจสอบเทียบกับเจ้าของและกลุ่มที่บันทึกไว้บนไฟล์ ไม่ใช่เทียบกับผู้ที่เขียนไฟล์นั้นเป็นคนสุดท้าย ให้รัน stat -c '%U %G %a %n' <file> เพื่อดูเจ้าของ กลุ่ม และโหมดสิทธิ์พร้อมกัน ก่อนที่คุณจะตัดสินใจว่าต้องใช้คำสั่งใดในสามคำสั่งนี้