рекурсивное разрешение chmod на тысячи файлов

16

Это более общий вопрос о 'chmoding' рекурсивно.

У меня есть этот скрипт, который в какой-то момент должен рекурсивно изменить разрешения в папке, которая имеет несколько сотен тысяч файлов. Новые файлы добавляются в эту папку каждый день, но те, которые уже есть, имеют уже установленные разрешения и не меняются.

Мой вопрос ... когда я звоню

чмод 775. -Р

пытается ли он установить разрешение для файлов, для которых уже установлены нужные разрешения, или только для новых файлов, которые не имеют необходимых разрешений?

Кажется, что для обхода этой команды в скрипте всегда требуются годы, хотя «новых» файлов всего несколько тысяч, и они должны делать свои разрешения довольно быстро.

Я посмотрел на страницу руководства по chmod, но в этом случае ничего не упоминается.

Если chmod не проверяет заранее разрешения, должен ли я начать смотреть на объединение 'find' с 'chmod'?

Тити Думи
источник
3
Интересно, действительно ли медленнее проверять разрешения и менять их, если они не верны, чем напрямую устанавливать их на правильное значение?
lgeorget
1
если кто-то наткнется на это и захочет найти команду find + chmod, вот она: find. ! -perm 775 -print0 | xargs -0 -I {} chmod 775 {}
Тити Думи
@lgeorget, значит, вы говорите, что медленнее использовать find | chmod? чем просто chmod все. (извините, не понял из вашего комментария). ура
Тити Думи
По моему скромному мнению, это, вероятно, медленнее, так как нужно запустить два процесса и перенаправить вывод первого на второй, но я не уверен. Это зависит от времени, которое требуется для установки разрешений, которые могут быть не столь важны, так как они всего 3 байта для изменения в inode.
lgeorget
1
@depquid Основной проблемой производительности здесь является чтение данных в дисковый кеш. После первого запуска все находится в дисковом кеше (если в нем недостаточно памяти), поэтому вы тестируете производительность чего-то, что не является узким местом в реальной ситуации.
Хауке Лагинг

Ответы:

9

chmodможет или не может изменить разрешения файлов, которые уже установлены на то, что вы хотите, но если нет, он все равно должен проверить их, чтобы увидеть, каковы их текущие разрешения [0]. С сотнями тысяч файлов, я не думаю, что это будет иметь значение в любом случае; время, скорее всего, тратится инструментами на statкаждый файл.

Вы можете попробовать использовать findлибо для проверки файлов новее, чем последний запуск, либо файлов, которые необходимо chmodзапустить, но я не думаю, что вы получите значительное улучшение скорости.

Если это возможно для вашего сценария, вы можете сначала поместить новые файлы в отдельную директорию, как область хранения. Тогда вы можете chmodТО каталог (в котором только новые файлы), и mvих вместе с остальными. Это должно быть значительно быстрее, но, к сожалению, не будет работать для каждого приложения.

[0] Даже если он попытается установить разрешение для файлов, которые не нуждаются в каких-либо изменениях, базовая файловая система, вероятно, ничего не сделает с запросом, потому что это не нужно.

МРБ
источник
Спасибо за это. Я попробую найти | версия chmod и посмотрим, будет ли она быстрее. Если нет, я попытаюсь изменить сценарий, чтобы реализовать папку «хранения», как вы предложили.
Тити Думи
Причина, по которой вы не получите улучшения скорости, заключается в том, что индекс должен быть прочитан как для ctime, так и для прав доступа.
Хауке Лагинг
10

оптимизация find / chmod

И то findи другое chmodчитать

  1. все записи каталога
  2. Иноды для всех этих записей

Вероятно, вы получите улучшение производительности, сначала прочитав все записи, а затем все inode (на вращающемся диске), потому что тогда головка диска не перемещается между каталогом и inode). Как chmod это глупо (как один из других ответов объясняет), следует назвать через findтолько. Но даже тогда это может помочь прочитать все inode до того, как будет записан первый (при условии, что у вас достаточно свободной оперативной памяти для дискового кэша). Я предлагаю это:

find . -printf "" # reading the file names only
find . ! -perm 775 -printf "" # reading all the inodes (file names are cached)
find . ! -perm 775 -exec chmod 775 + # writing to the cache without reading from disk

Хорошее решение: списки ACL

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

Дальнейшее улучшение может быть достигнуто за счет оптимизации файловой системы. Если это ext3 / ext4, то вы можете запускать e2fsck -Dвремя от времени. Может быть, это поможет поместить этот каталог на отдельный том. Вы можете попробовать разные файловые системы или настройки файловой системы (например, разные размеры inode).

Хауке Лагинг
источник
ACL хороши, если вы не работаете с монтированием NFSv4.
Острокач
findРешение о удвоилась мое время, chmodИНГ внутри Docker контейнера.
Натан ReinstateMonica Arthur
8

Если предположить , что использование chmodиз пакета GNU Coreutils на Ubuntu 12.10.

chmod 775 . -Rвыполняет fchmodatсистемный вызов для каждого файла, который он находит, независимо от того, нужно ли изменять разрешения или нет. Я подтвердил это, проверив код и используя strace chmod 775 . -R(фрагмент ниже) для отображения фактического поведения.

newfstatat(4, "d", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "d", 0775)                  = 0
newfstatat(4, "c", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "c", 0775)                  = 0
newfstatat(4, "a", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "a", 0775)                  = 0
newfstatat(4, "b", {st_mode=S_IFREG|0666, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
fchmodat(4, "b", 0775)                  = 0

Есть несколько недостатков запуска fchmodatкаждого файла.

  • Дополнительный системный вызов, вероятно, станет значительным, если будет изменено большое количество файлов. Метод find/ xargs/, chmodупомянутый другими, скорее всего, будет быстрее, изменяя только те файлы, которые нужно изменить.
  • Вызов fchmodatизменяет изменение статуса файла (ctime) каждого файла. Это приведет к тому, что каждый файл / индекс будет меняться каждый раз и, вероятно, приведет к избыточной записи на диск. Может быть возможно использовать параметры монтирования, чтобы остановить эти лишние записи.

Простой эксперимент показывает изменения ctime, происходящие для прямой chmod

auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:17 d
auser@duncow:/tmp/blah.test$ chmod 775 . -R
auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 d

Но это не изменится find/ xargs/ chmodчерез несколько минут

auser@duncow:/tmp/blah.test$ date
Tue Jun 18 18:27:27 BST 2013
auser@duncow:/tmp/blah.test$ find . ! -perm 775 -print0 | xargs -0 -I {} chmod 775 {}
auser@duncow:/tmp/blah.test$ ls -lc
total 0
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 a
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 b
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 c
-rwxrwxr-x 1 laptop laptop 0 Jun 18 18:25 d

Я всегда склонен использовать find/ xargs/ chmodверсию, потому что поиск дает больше контроля над выбором вещей.

Richm
источник
1

[Source] (1) показывает, что chmod(1)всегда пытается установить режим, а затем проверяет снова с помощью [fstatat (2)] (2).

Файлы обрабатываются с помощью [fts (3)] (3), который должен предварительно "просчитать" все пройденные объекты файловой системы, чтобы построить свое дерево данных.

В Unixlore есть [хорошая статья] (4), chmod(1)которая рассчитана против подхода find/ xargs: последний выигрывает по величине.

Здесь командная строка адаптирована к исходному вопросу:

find . -print0 | xargs -0 chmod 775

Две причины:

  1. Обход файловой системы отделен от операций над файлами по каналу между двумя процессами, которые могут даже выполняться на разных ядрах.

    1. fts(3)операция сводится к минимуму, потому что xargs(1)«выравнивает» дерево каталогов.

Так что да: вы должны обязательно использовать find/ xargs. для простого решения.

Другие опции:

  • Поиграйте с [umask] (5) и исходным кодом процесса (ов), пишущих новые файлы.

  • Если вы используете Linux, скорее всего, ваша система inotifyвключила подсистему ядра. В этом случае вы можете написать эффективное решение с помощью [inotifywait (1)] (6).


Примечание: если вы не хотите разрешать выполнение ваших файлов, я бы предложил изменить вызов следующим образом:

find . -type f -print0 | xargs -0 chmod 664
find . -type d -print0 | xargs -0 chmod 775

Примечание для редакторов: я не имею права добавлять более двух ссылок на сообщение, а также комментировать другие сообщения. Я оставляю здесь ссылки и надеюсь, что какой-нибудь открытый человек с достаточной репутацией вернет их обратно в текст и удалит этот абзац.


Комментарий на грунтования кэш диска с find . -printf "":

Это может ускорить выполнение следующих chmodопераций, однако зависит от доступной памяти и загрузки ввода-вывода. Так может сработать или нет. Разделение traversal ( find) и chmodоперации уже обеспечивает кэширование, поэтому заполнение кэша может быть излишним.

  1. HTTPS + lingrok.org / Xref / Coreutils / SRC / chmod.c # process_file
  2. HTTPS + linux.die.net / человек / 2 / fstatat
  3. HTTPS + linux.die.net / человек / 3 / FTS
  4. HTTP + www.unixlore.net / статьи / ускорение вверх-балк-файлы operations.html
  5. HTTPS + en.wikipedia.org / вики / Umask
  6. HTTPS + linux.die.net / человек / 1 / inotifywait
Георг Ленер
источник
0

Рассматривали ли вы изменение процесса (ов), которые создают файл, чтобы они были созданы в режиме 0775? Посмотрите на значение umask в окружающей среде - 0002 может помочь.

D МакКеон
источник