Bagaimana cara chmod secara rekursif semua direktori kecuali file?

Jawaban:

802

Untuk secara rekursif memberikan direktori hak baca & eksekusi:

find /path/to/base/dir -type d -exec chmod 755 {} +

Untuk secara rekursif memberikan file hak istimewa baca:

find /path/to/base/dir -type f -exec chmod 644 {} +

Atau, jika ada banyak objek untuk diproses:

chmod 755 $(find /path/to/base/dir -type d)
chmod 644 $(find /path/to/base/dir -type f)

Atau, untuk mengurangi chmodpemijahan:

find /path/to/base/dir -type d -print0 | xargs -0 chmod 755 
find /path/to/base/dir -type f -print0 | xargs -0 chmod 644
nik
sumber
7
Dua contoh pertama gagal untuk direktori dengan terlalu banyak file: -bash: /bin/chmod: Argument list too long. Perintah terakhir bekerja dengan banyak file, tetapi ketika menggunakan sudosalah satu harus berhati-hati untuk meletakkannya sebelum xargs bukannya chmod:find /path/to/base/dir -type d -print0 | sudo xargs -0 chmod 755
Agargara
2
Juga untuk dicatat, perintah-perintah ini sudah termasuk dir dasar. Jadi dalam contoh di atas, dirjuga akan diatur ke 755.
CenterOrbit
2
chmod ... $(find /path/to/base/dir -type ...)gagal untuk nama file dengan spasi di namanya.
Dan Dascalescu
7
Saya pikir versi yang paling benar (tetapi tidak tercepat) sehubungan dengan spasi dan simbol dalam nama file dan jumlah file adalah find /path/to/base/dir -type d -exec chmod 755 {} \;( find /path/to/base/dir -type f -exec chmod 644 {} \;).
Peter K
Perhatikan bahwa ini hanya menuju lapisan pertama yang bisa dibaca. Anda harus menjalankannya beberapa kali untuk masuk lebih dalam ke pohon direktori.
Henk Poley
290

Alasan umum untuk hal semacam ini adalah untuk mengatur direktori ke 755 tetapi file ke 644. Dalam hal ini ada cara yang sedikit lebih cepat daripada findcontoh nik :

chmod -R u+rwX,go+rX,go-w /path

Berarti:

  • -R = secara rekursif;
  • u+rwX = Pengguna dapat membaca, menulis, dan mengeksekusi;
  • go+rX = grup dan yang lainnya dapat membaca dan mengeksekusi;
  • go-w = grup dan yang lain tidak bisa menulis

Yang penting untuk dicatat di sini adalah bahwa huruf besar Xtindakan berbeda untuk huruf kecil x. Secara manual kita bisa membaca:

Bit eksekusi / pencarian jika file tersebut adalah direktori atau salah satu bit eksekusi / pencarian diatur dalam mode asli (tidak dimodifikasi).

Dengan kata lain, chmod u + X pada file tidak akan mengatur bit eksekusi; dan g + X hanya akan mengaturnya jika sudah ditetapkan untuk pengguna.

bobince
sumber
5
-R = secara rekursif; u + rwX = Pengguna dapat membaca, menulis, dan mengeksekusi; go + rX = grup dan orang lain dapat membaca dan mengeksekusi; go-w = grup dan yang lain tidak bisa menulis
släcker
23
Pola ini tidak akan memperbaiki situasi ketika seseorang telah melakukannya chmod -R 777karena +Xopsi tidak akan mereset bit eksekusi yang ada pada file. Menggunakan -x akan mengatur ulang direktori, dan mencegahnya.
Andrew Vit
3
@ ring0: Saya tidak bermaksud menjawab pertanyaan secara harfiah seperti yang diajukan - nik telah melakukannya dengan sangat baik. Saya menunjukkan solusi yang lebih murah untuk kasus yang paling umum. Dan ya, Anda mendapatkan izin yang berbeda untuk file dan direktori X, seperti yang dijelaskan dalam komentar.
bobince
6
go+rX,go-w-> go=rXbukan?
Pierre de LESPINAY
5
Anda juga dapat menggunakan chmod u-x,u+Xdalam kombinasi, dll., Untuk menghapus bit eksekusi untuk file, tetapi menambahkannya untuk direktori.
w0rp
14

Jika Anda ingin memastikan file diatur ke 644 dan ada file di jalur yang memiliki flag eksekusi, Anda harus menghapus flag eksekusi terlebih dahulu. + X tidak menghapus flag eksekusi dari file yang sudah memilikinya.

Contoh:

chmod -R ugo-x,u+rwX,go+rX,go-w path

Pembaruan: ini tampaknya gagal karena perubahan pertama (ugo-x) membuat direktori tidak dapat dieksekusi, sehingga semua file di bawahnya tidak berubah.

mpolden
sumber
1
Ini bekerja untuk saya, dan saya tidak mengerti mengapa tidak. (Tentu, jika Anda melakukannya saja chmod -R ugo-x path, itu mungkin menjadi masalah. Tetapi perintah lengkap akan melakukan chmod u+rwXpada setiap direktori sebelum mencoba turun ke dalamnya.) Namun, saya percaya itu chmod R u=rw,go=r,a+X pathsudah cukup - dan lebih pendek.
Scott
Saya menemukan ini berfungsi dengan baik; tidak ada masalah dengan memasukkan direktori
Seseorang Di Suatu Tempat
4

Saya memutuskan untuk menulis naskah kecil untuk ini sendiri.

Skrip chmod rekursif untuk dir dan / atau file - Inti :

chmodr.sh

#!/bin/sh
# 
# chmodr.sh
#
# author: Francis Byrne
# date: 2011/02/12
#
# Generic Script for recursively setting permissions for directories and files
# to defined or default permissions using chmod.
#
# Takes a path to recurse through and options for specifying directory and/or 
# file permissions.
# Outputs a list of affected directories and files.
# 
# If no options are specified, it recursively resets all directory and file
# permissions to the default for most OSs (dirs: 755, files: 644).

# Usage message
usage()
{
  echo "Usage: $0 PATH -d DIRPERMS -f FILEPERMS"
  echo "Arguments:"
  echo "PATH: path to the root directory you wish to modify permissions for"
  echo "Options:"
  echo " -d DIRPERMS, directory permissions"
  echo " -f FILEPERMS, file permissions"
  exit 1
}

# Check if user entered arguments
if [ $# -lt 1 ] ; then
 usage
fi

# Get options
while getopts d:f: opt
do
  case "$opt" in
    d) DIRPERMS="$OPTARG";;
    f) FILEPERMS="$OPTARG";;
    \?) usage;;
  esac
done

# Shift option index so that $1 now refers to the first argument
shift $(($OPTIND - 1))

# Default directory and file permissions, if not set on command line
if [ -z "$DIRPERMS" ] && [ -z "$FILEPERMS" ] ; then
  DIRPERMS=755
  FILEPERMS=644
fi

# Set the root path to be the argument entered by the user
ROOT=$1

# Check if the root path is a valid directory
if [ ! -d $ROOT ] ; then
 echo "$ROOT does not exist or isn't a directory!" ; exit 1
fi

# Recursively set directory/file permissions based on the permission variables
if [ -n "$DIRPERMS" ] ; then
  find $ROOT -type d -print0 | xargs -0 chmod -v $DIRPERMS
fi

if [ -n "$FILEPERMS" ] ; then
  find $ROOT -type f -print0 | xargs -0 chmod -v $FILEPERMS
fi

Ini pada dasarnya melakukan chmod rekursif tetapi juga memberikan sedikit fleksibilitas untuk opsi baris perintah (mengatur direktori dan / atau izin file, atau mengecualikan keduanya secara otomatis me-reset semuanya ke 755-644). Itu juga memeriksa beberapa skenario kesalahan.

Saya juga menulis tentang itu di blog saya .

francisbyrne
sumber
2

Untuk secara rekursif memberikan direktori hak baca & eksekusi:

find /path/to/base/dir -type d -exec chmod 755 {} \;

Untuk secara rekursif memberikan file hak istimewa baca:

find /path/to/base/dir -type f -exec chmod 644 {} \;

Lebih baik terlambat daripada tidak pernah membiarkan saya meningkatkan jawaban nik di sisi kebenaran. Solusi saya lebih lambat, tetapi berfungsi dengan sejumlah file, dengan simbol apa pun dalam nama file, dan Anda dapat menjalankannya dengan sudo secara normal (tetapi berhati-hatilah bahwa ia mungkin menemukan file yang berbeda dengan sudo).

Peter K.
sumber
Ini adalah downgrade dari jawaban nik . Mengapa Anda percaya bahwa ada yang salah dengan jawaban nik?
Scott
@Scott, jawaban nik gagal dengan (vey) sejumlah besar file.
Peter K
Saya 99% yakin Anda salah. Bisakah Anda memberikan bukti untuk mendukung klaim Anda?
Scott
Ya, sepertinya saya salah. temukan ... + tampaknya memecah baris menjadi beberapa perintah, tangkapan bagus!
Peter K
0

Coba skrip python ini; tidak memerlukan proses pemijahan dan hanya melakukan dua syscalls per file. Terlepas dari implementasi dalam C, itu mungkin akan menjadi cara tercepat untuk melakukannya (saya membutuhkannya untuk memperbaiki sistem file 15 juta file yang semuanya diatur ke 777)

#!/usr/bin/python3
import os
for par, dirs, files in os.walk('.'):
    for d in dirs:
        os.chmod(par + '/' + d, 0o755)
    for f in files:
        os.chmod(par + '/' + f, 0o644)

Dalam kasus saya, coba / tangkap diperlukan di sekitar chmod terakhir, karena chmodding beberapa file khusus gagal.

mic_e
sumber
-1

Anda juga dapat menggunakan tree:

tree -faid /your_directory | xargs -L1 -I{} bash -c 'sudo chmod 755 "$1"' -- '{}'

dan jika Anda juga ingin melihat folder tambahkan gema

 tree -faid /your_directory | xargs -L1 -I{} bash -c 'sudo chmod 755 "$1" && echo$1' -- '{}'
Eduard Florinescu
sumber
@Scott 1) ​​Anda benar tentang + x saya berubah menjadi 755; 2) 3) untuk menyelesaikan ini, saya letakkan placeholder dalam kutipan tunggal seperti ini '{}'
Eduard Florinescu
@Scott Saya setuju ini bukan jawaban terbaik juga lambat tetapi akan pergi ke sini untuk tujuan "didaktik" juga komentar akan menjelaskan lebih lanjut, juga orang dapat belajar tentang xargsmasalah. Kutipan tunggal dalam nama file sendiri merupakan masalah bagi banyak perintah dan skrip itu sebabnya saya mendaftarkan semua file yang berisi tanda kutip tunggal dan menghapusnya (tanda kutip yang saya maksud)
Eduard Florinescu
@Scott Pada sistem saya, saya mencari semua file yang berisi tanda kutip tunggal dan mengganti tanda kutip tunggal
Eduard Florinescu
@Scott Bagaimana Anda memperbaiki fakta bahwa xargs tidak menyelesaikan dengan benar tanda kutip tunggal?
Eduard Florinescu
Mari kita lanjutkan diskusi ini dalam obrolan .
Eduard Florinescu
-2

Anda bisa menggunakan skrip bash berikut sebagai contoh. Pastikan untuk memberikannya izin yang dapat dieksekusi (755). Cukup gunakan ./autochmod.sh untuk direktori saat ini, atau ./autochmod.sh <dir> untuk menentukan yang lain.

#!/bin/bash

if [ -e $1 ]; then
    if [ -d $1 ];then
        dir=$1
    else
        echo "No such directory: $1"
        exit
    fi
else
    dir="./"
fi

for f in $(ls -l $dir | awk '{print $8}'); do
    if [ -d $f ];then
        chmod 755 $f
    else
        chmod 644 $f
    fi
done
pengguna26528
sumber
2
Wow! Begitu banyak masalah! (1) Jika $1bukan null, tetapi bukan nama direktori (mis. Adalah salah ketik), maka dirakan diatur ke .tanpa pesan. (2) $1harus "$1"dan $dirseharusnya "$dir". (3) Anda tidak perlu mengatakan "./"; "."baik-baik saja (dan, sebenarnya, Anda tidak perlu penawaran di sini). (4) Ini bukan solusi rekursif. (5) Di sistem saya, ls -l … | awk '{ print $8 }'dapatkan waktu modifikasi file. Anda harus { print $9 }mendapatkan kata pertama dari nama file. Dan bahkan kemudian, (6) ini tidak menangani nama file dengan ruang putih. ...
Scott
1
... Dan, yang tak kalah (∞) jika skrip ini berada di direktori saat ini, itu akan chmod sendiri ke 644, sehingga membuat sendiri non-executable!
Scott