Как рекурсивно выполнить chmod все каталоги, кроме файлов?

576

Как chmod 755 все каталоги, но нет файла (рекурсивно)?

И наоборот, как chmod только файлы (рекурсивно), но без каталога?

Оливье Лалонд
источник

Ответы:

802

Чтобы рекурсивно дать каталогам права на чтение и выполнение:

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

Чтобы рекурсивно дать файлам права на чтение:

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

Или, если есть много объектов для обработки:

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

Или, чтобы уменьшить chmodнерест:

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
источник
7
Первые два примера обязательно для каталогов со слишком большим количеством файлов: -bash: /bin/chmod: Argument list too long. Последняя команда работает со многими файлами, но при ее использовании sudoнужно быть осторожнее, чтобы поместить ее перед xargs вместо chmod:find /path/to/base/dir -type d -print0 | sudo xargs -0 chmod 755
Agargara
2
Также к сведению, эти команды с учетом базовой директории. Так что в приведенном выше примере dirтакже будет установлено значение 755.
CenterOrbit
2
chmod ... $(find /path/to/base/dir -type ...)не удается для имен файлов с пробелами в имени.
Дан Даскалеску
7
Я думаю, что наиболее правильной (но не самой быстрой) версией в отношении пробелов и символов в именах файлов и количестве файлов является find /path/to/base/dir -type d -exec chmod 755 {} \;( find /path/to/base/dir -type f -exec chmod 644 {} \;).
Питер К
Обратите внимание, что это относится только к первому слою, который он может прочитать. Вам придется выполнить его несколько раз, чтобы глубже проникнуть в дерево каталогов.
Хенк Поли
290

Распространенной причиной такого рода вещей является установка каталогов на 755, а файлов на 644. В этом случае есть несколько более быстрый способ, чем в findпримере с nik :

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

Смысл:

  • -R = рекурсивно;
  • u+rwX = Пользователи могут читать, писать и выполнять;
  • go+rX = группа и другие могут читать и выполнять;
  • go-w = группа и другие не могут писать

Здесь важно отметить, что прописные буквы Xдействуют не так, как строчные x. В руководстве мы можем прочитать:

Биты выполнения / поиска, если файл является каталогом, или любой из битов выполнения / поиска установлены в исходном (неизмененном) режиме.

Другими словами, chmod u + X в файле не устанавливает бит выполнения; и g + X установит его, только если он уже установлен для пользователя.

bobince
источник
5
-R = рекурсивно; u + rwX = Пользователи могут читать, писать и выполнять; go + rX = group и другие могут читать и выполнять; go-w = group и другие не могут писать
släcker
23
Этот шаблон не исправит ситуацию, когда кто-то сделал, chmod -R 777так как +Xопция не будет сбрасывать существующие биты выполнения для файлов. Использование -x сбросит каталоги и предотвратит спуск в них.
Андрей Вит
3
@ ring0: я не собираюсь отвечать на вопрос буквально, как задано - nik уже сделал это на отлично. Я указываю на более дешевое решение для наиболее распространенного случая. И да, вы получаете разные разрешения для файлов и каталогов с помощью X, как объяснено в комментариях.
bobince
6
go+rX,go-w-> go=rXне так ли?
Пьер де ЛЕСПИНАЙ
5
Вы также можете использовать их chmod u-x,u+Xв комбинации и т. Д., Чтобы удалить биты выполнения для файлов, но добавить их для каталогов.
w0rp
14

Если вы хотите убедиться, что для файлов установлено значение 644, а в пути есть файлы с флагом выполнения, вам сначала нужно удалить флаг выполнения. + X не удаляет флаг выполнения из файлов, у которых он уже есть.

Пример:

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

Обновление: кажется, что это не удалось, потому что первое изменение (ugo-x) делает каталог неисполнимым, поэтому все файлы под ним не изменяются.

mpolden
источник
1
Это работает для меня, и я не понимаю, почему это не так. (Конечно, если вы это сделали chmod -R ugo-x path, это может быть проблемой. Но полная команда выполнит все действия в chmod u+rwXкаждом каталоге, прежде чем попытаться спуститься в него.) Однако я считаю, что этого chmod R u=rw,go=r,a+X pathдостаточно - и оно короче.
Скотт
Я обнаружил, что это работает правильно; не было проблем с входом в каталоги
Someone Somewhere
4

Я решил написать небольшой сценарий для этого сам.

Рекурсивный скрипт chmod для директорий и / или файлов - 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

Он в основном делает рекурсивный chmod, но также обеспечивает некоторую гибкость для параметров командной строки (устанавливает права доступа к каталогу и / или файлу или исключает оба, он автоматически сбрасывает все до 755-644). Он также проверяет несколько сценариев ошибок.

Я также написал об этом в своем блоге .

francisbyrne
источник
2

Чтобы рекурсивно дать каталогам права на чтение и выполнение:

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

Чтобы рекурсивно дать файлам права на чтение:

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

Лучше поздно, чем никогда, позвольте мне обновить ответ Ника на правильность. Мое решение медленнее, но оно работает с любым количеством файлов, с любыми символами в именах файлов, и вы можете запустить его с помощью sudo в обычном режиме (но помните, что он может обнаружить другие файлы с помощью sudo).

Питер К
источник
Это понижение в ответ для Nik . Почему вы считаете, что с ответом Ника что-то не так?
Скотт
@ Scott, ответ nik терпит неудачу с (очень) большим количеством файлов.
Питер К
Я на 99% уверен, что вы ошибаетесь. Можете ли вы предоставить какие-либо доказательства в поддержку вашего требования?
Скотт
Да, похоже, я действительно неправ. найти ... +, кажется, разбить строку на несколько команд, хороший улов!
Питер К
0

Попробуйте этот скрипт на Python; он не требует порождения процессов и выполняет только два системных вызова на файл. Помимо реализации в C, это, вероятно, будет самый быстрый способ сделать это (мне нужно было исправить файловую систему из 15 миллионов файлов, все из которых были настроены на 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)

В моем случае попытка / отлов потребовалась для последнего chmod, так как chmodding некоторых специальных файлов не удался.

мышей
источник
-1

Вы также можете использовать tree:

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

и если вы хотите также просмотреть папку, добавьте эхо

 tree -faid /your_directory | xargs -L1 -I{} bash -c 'sudo chmod 755 "$1" && echo$1' -- '{}'
Эдуард Флоринеску
источник
@ Скотт 1) Вы правы насчет + х я изменил на 755; 2) 3) чтобы решить эту проблему, я поместил заполнитель в одинарную кавычку, например: '{}'
Эдуард Флоринеску
@ Скотт Я согласен, что это не самый лучший ответ, и он слишком медленный, но он уйдет сюда для «дидактических» целей, также комментарии будут объяснены далее, также люди могут узнать о xargsпроблемах. Одиночные кавычки в именах файлов сами по себе являются проблемой для многих команд и сценариев, поэтому я перечислил все файлы, содержащие одинарные кавычки, и удалил их (я имею в виду кавычки)
Эдуард Флоринеску
@Scott В моих системах я искал все файлы, которые содержали одинарные кавычки, и заменил одинарные кавычки
Эдуард Флоринеску
@ Скотт Как бы вы исправили тот факт, что xargs неправильно решает одинарные кавычки?
Эдуард Флоринеску
Давайте продолжим эту дискуссию в чате .
Эдуард Флоринеску
-2

Вы можете использовать следующий скрипт bash в качестве примера. Обязательно дайте ему исполняемые разрешения (755). Просто используйте ./autochmod.sh для текущего каталога или ./autochmod.sh <dir>, чтобы указать другой.

#!/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
источник
2
Вау! Так много проблем! (1) Если значение $1не равно нулю, но не является именем каталога (например, является опечаткой), то dirустанавливается значение .без сообщения. (2) $1должно быть "$1"и $dirдолжно быть "$dir". (3) Вам не нужно говорить "./"; "."хорошо (и, строго говоря, здесь вам не нужны кавычки). (4) Это не рекурсивное решение. (5) В моей системе ls -l … | awk '{ print $8 }'получает время модификации файлов. Вам нужно { print $9 }получить первое слово в имени файла. И даже тогда (6) это не обрабатывает имена файлов с пробелами. …
Скотт
1
И, наконец, что не менее важно (∞), если этот сценарий находится в текущем каталоге, он chmod сам перейдет к 644, что сделает его неисполняемым!
Скотт