Wie chmod rekursiv alle Verzeichnisse mit Ausnahme von Dateien?

Antworten:

801

So geben Sie Verzeichnissen rekursiv Lese- und Ausführungsrechte:

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

So erteilen Sie Dateien rekursiv Leserechte:

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

Oder wenn es viele zu verarbeitende Objekte gibt:

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

Oder, um das chmodLaichen zu reduzieren :

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
quelle
7
Die ersten beiden Beispiele nicht für Verzeichnisse mit zu vielen Dateien: -bash: /bin/chmod: Argument list too long. Der letzte Befehl funktioniert mit vielen Dateien, aber wenn Sie sudoeinen verwenden, müssen Sie darauf achten, ihn vor xargs anstelle von chmod zu setzen:find /path/to/base/dir -type d -print0 | sudo xargs -0 chmod 755
Agargara
2
Auch zu beachten, diese Befehle sind inklusive der Basis Richt. So wird im obigen Beispiel dirauch auf 755 gesetzt.
CenterOrbit
2
chmod ... $(find /path/to/base/dir -type ...)schlägt bei Dateinamen mit Leerzeichen im Namen fehl.
Dan Dascalescu
7
Ich denke, die korrekteste (aber nicht schnellste) Version in Bezug auf Leerzeichen und Symbole in Dateinamen und Anzahl der Dateien ist find /path/to/base/dir -type d -exec chmod 755 {} \;( find /path/to/base/dir -type f -exec chmod 644 {} \;).
Peter K
Beachten Sie, dass dies nur für die erste Ebene gilt, die gelesen werden kann. Sie müssen es mehrmals ausführen, um tiefer in den Verzeichnisbaum zu gelangen.
Henk Poley
290

Ein häufiger Grund dafür ist, dass Verzeichnisse auf 755 und Dateien auf 644 gesetzt werden. In diesem Fall gibt es einen etwas schnelleren Weg als in Niks findBeispiel:

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

Bedeutung:

  • -R = rekursiv;
  • u+rwX = Benutzer können lesen, schreiben und ausführen;
  • go+rX = Gruppe und andere können lesen und ausführen;
  • go-w = Gruppe und andere können nicht schreiben

Wichtig hierbei ist, dass sich Groß- Xund Kleinschreibung unterscheiden x. Im Handbuch können wir lesen:

Die Ausführungs- / Suchbits, wenn die Datei ein Verzeichnis ist, oder eines der Ausführungs- / Suchbits werden in den ursprünglichen (nicht modifizierten) Modus versetzt.

Mit anderen Worten, chmod u + X in einer Datei setzt das Ausführungsbit nicht. und g + X setzt es nur, wenn es bereits für den Benutzer eingestellt ist.

Bobince
quelle
5
-R = rekursiv; u + rwX = Benutzer können lesen, schreiben und ausführen; go + rX = group und andere können lesen und ausführen; go-w = group und andere können nicht schreiben
släcker
23
Dieses Muster behebt nicht die Situation, die jemand getan hat, chmod -R 777da die +XOption vorhandene Ausführungsbits für Dateien nicht zurücksetzt. Mit -x werden Verzeichnisse zurückgesetzt und ein Abstieg in diese verhindert.
Andrew Vit
3
@ ring0: Ich habe nicht die Absicht, die Frage buchstäblich so zu beantworten, wie sie gestellt wurde - Nik hat das bereits perfekt gemacht. Ich weise auf eine billigere Lösung für den häufigsten Fall hin. Und ja, Sie erhalten unterschiedliche Berechtigungen für Dateien und Verzeichnisse X, wie in den Kommentaren erläutert.
Bobince
6
go+rX,go-w-> go=rXnicht wahr
Pierre de LESPINAY
5
Sie können auch chmod u-x,u+Xin Kombination usw. verwenden, um Ausführungsbits für Dateien zu entfernen, diese jedoch für Verzeichnisse hinzuzufügen.
w0rp
14

Wenn Sie sicherstellen möchten, dass die Dateien auf 644 gesetzt sind und sich im Pfad Dateien mit dem Ausführungsflag befinden, müssen Sie zuerst das Ausführungsflag entfernen. + X entfernt das Ausführungsflag nicht von Dateien, die es bereits haben.

Beispiel:

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

Update: Dies scheint zu scheitern, da das Verzeichnis bei der ersten Änderung (ugo-x) nicht mehr ausführbar ist, sodass alle Dateien darunter nicht geändert werden.

mpolden
quelle
1
Das funktioniert bei mir und ich verstehe nicht warum. (Sicher, wenn Sie das getan chmod -R ugo-x pathhaben, könnte das ein Problem sein. Aber der vollständige Befehl führt das chmod u+rwXin jedem Verzeichnis aus, bevor er versucht, in dieses Verzeichnis zu gelangen.) Ich glaube jedoch, dass dies chmod R u=rw,go=r,a+X pathausreicht - und dass es kürzer ist.
Scott
Ich fand das richtig funktioniert; Es gab keine Probleme beim Eingeben von Verzeichnissen
Someone Somewhere
4

Ich beschloss, selbst ein kleines Skript dafür zu schreiben.

Rekursives chmod-Skript für Verzeichnisse und / oder Dateien - Gist :

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

Es führt im Grunde genommen das rekursive chmod aus, bietet aber auch ein wenig Flexibilität für Befehlszeilenoptionen (setzt Verzeichnis- und / oder Dateiberechtigungen oder schließt beides aus, setzt automatisch alles auf 755-644 zurück). Es wird auch nach einigen Fehlerszenarien gesucht.

Ich habe auch in meinem Blog darüber geschrieben .

Francisbyrne
quelle
2

So geben Sie Verzeichnissen rekursiv Lese- und Ausführungsrechte:

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

So erteilen Sie Dateien rekursiv Leserechte:

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

Besser spät als nie lass mich Niks Antwort auf die Seite der Korrektheit bringen. Meine Lösung ist langsamer, funktioniert aber mit einer beliebigen Anzahl von Dateien, mit beliebigen Symbolen in Dateinamen, und Sie können sie normal mit sudo ausführen (achten Sie jedoch darauf, dass mit sudo möglicherweise andere Dateien erkannt werden).

Peter K
quelle
Dies ist eine Herabstufung von Niks Antwort . Warum glaubst du, dass mit Niks Antwort etwas nicht stimmt?
Scott
@Scott, die Antwort von nik schlägt mit (sehr) vielen Dateien fehl.
Peter K
Ich bin mir zu 99% sicher, dass Sie sich irren. Können Sie Beweise für Ihre Behauptung vorlegen?
Scott
Ja, es sieht so aus, als ob ich tatsächlich falsch liege. find ... + scheint die Zeile in mehrere Befehle aufzuteilen, nice catch!
Peter K
0

Probieren Sie dieses Python-Skript aus. Es erfordert kein Spawnen von Prozessen und führt nur zwei Systemaufrufe pro Datei aus. Abgesehen von einer Implementierung in C wird dies wahrscheinlich der schnellste Weg sein (ich brauchte ihn, um ein Dateisystem mit 15 Millionen Dateien zu reparieren, die alle auf 777 gesetzt waren).

#!/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)

In meinem Fall war um das letzte chmod ein try / catch erforderlich, da das chmodding einiger spezieller Dateien fehlgeschlagen ist.

Mäuse
quelle
-1

Sie können auch verwenden tree:

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

und wenn Sie auch den Ordner anzeigen möchten, fügen Sie ein Echo hinzu

 tree -faid /your_directory | xargs -L1 -I{} bash -c 'sudo chmod 755 "$1" && echo$1' -- '{}'
Eduard Florinescu
quelle
@Scott 1) ​​Sie haben recht mit + x Ich habe auf 755 gewechselt; 2) 3) um dies zu lösen, setze ich den Platzhalter in ein einfaches Anführungszeichen wie dieses '{}'
Eduard Florinescu
@Scott Ich bin damit einverstanden, dass dies nicht die beste Antwort ist, die auch langsam ist, aber ich werde hier aus "didaktischen" Gründen auch die Kommentare näher erläutern, auch die Leute können sich über xargsThemen informieren. Einfache Anführungszeichen in Dateinamen sind selbst ein Problem für viele Befehle und Skripte, deshalb habe ich alle Dateien mit einfachen Anführungszeichen aufgelistet und entfernt (die Anführungszeichen meine ich)
Eduard Florinescu
@Scott Auf meinen Systemen suchte ich nach allen Dateien, die einfache Anführungszeichen enthielten, und ersetzte die einfachen Anführungszeichen
Eduard Florinescu
@Scott Wie können Sie die Tatsache beheben, dass xargs die einzelnen Anführungszeichen nicht korrekt löst?
Eduard Florinescu
Lassen Sie uns diese Diskussion im Chat fortsetzen .
Eduard Florinescu
-2

Sie können das folgende Bash-Skript als Beispiel verwenden. Stellen Sie sicher, dass Sie ihm ausführbare Berechtigungen erteilen (755). Verwenden Sie einfach ./autochmod.sh für das aktuelle Verzeichnis oder ./autochmod.sh <dir>, um ein anderes Verzeichnis anzugeben.

#!/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
user26528
quelle
2
Beeindruckend! So viele Probleme! (1) Wenn $1nicht null ist, sondern nicht der Name eines Verzeichnisses (z. B. ein Tippfehler), dirwird .ohne Meldung auf gesetzt. (2) $1sollte "$1"und $dirsollte sein "$dir". (3) Sie brauchen nicht zu sagen "./"; "."ist in Ordnung (und genau genommen brauchen Sie hier keine Anführungszeichen). (4) Dies ist keine rekursive Lösung. (5) Ruft auf meinem System ls -l … | awk '{ print $8 }'die Änderungszeiten der Dateien ab. Sie müssen { print $9 }bekommen , das erste Wort von dem Dateinamen. Und selbst dann (6) behandelt dies keine Dateinamen mit Leerzeichen. …
Scott
1
… Und, last but not least (∞), wenn sich dieses Skript im aktuellen Verzeichnis befindet, wird es chmod selbst auf 644 gesetzt, wodurch es selbst nicht ausführbar wird!
Scott