Как выразить тесты `find`'s -writable и -readable, если они недоступны?

Как выразить тесты `find`'s -writable и -readable, если они недоступны?

Иногда на старых системах Linux я сталкиваюсь с тем, что findне поддерживаются -writableтесты -readable, которые проверяют, доступен ли файл или каталог для записи/чтения для текущего пользователя.

Допустим, я хочу выразить -writable; тогда -perm -0002это не будет эквивалентно, так как не проверяется, есть ли у пользователя права на запись с помощью владельца/группы.

Как я могу выразить findтест -writableс помощью findдругих тестов (например -perm, )?

решение1

Нет удобного способа. Вот почему GNU find добавил -readableи друзей.

Вы можете построить выражение, которое приблизительно соответствует тесту разрешений, перечислив группы, в которых состоит пользователь. Не проверено.

can_access="( -user $(id -u) -perm -0${oct}00 -o ("
for g in $(id -G); do
  can_access="$can_access -group $g -o"
done
can_access="${can_access% -o} ) -perm -00${oct}0 -o -perm -000${oct} )"
find … $can_access -print

Это не дает правильного результата в некоторых случаях, например, если есть списки контроля доступа или в крайних случаях, например, -rw----r--для запрета доступа группе. Вы можете проверить крайние случаи с помощью той же техники, что и выше, но выражение становится еще сложнее. Для списков контроля доступа вам нужно вызвать инструмент, который их поддерживает.

Такие языки, как Perl и Python, обеспечивают легкий доступ как к access(2)функции, так и к функциональным возможностям find. В Perl, сFile::Findи-r/ -w/-x(которые используют эффективные uid и gid процесса Perl — используйте -R/ -W/ -Xдля проверки с реальным uid/gid, как и access(2), и используйтеfiletest 'access'прагмаесли ваш Perl не слишком древний, чтобы поддерживать такие вещи, как ACL):

use File::Find;
use filetest 'access';
find(sub { if (-r $_) { print "$_ is readable\n"; } }, '.');

В Python, сos.walkиos.access(который использует реальные uid и gid процесса Python, например access(2)):

import os
for dirpath, dirnames, filenames in os.walk('.', ):
    for filename in filenames:
        filename = os.path.join(dirpath, filenames)
        if os.access(filename, os.R_OK):
            print(filename + ' is readable\n')

Единственный полностью надежный способ — попытаться открыть файл. Для этого нужна внешняя утилита, поэтому это будет медленнее. Чтобы проверить читаемость обычного файла:

find … -exec sh -c 'exec 2>/dev/null; : <"$0"' {} \; …

Для проверки возможности записи используйте : >>"$0"(это открывает файл для добавления, поэтому проверка завершится неудачей, если файл недоступен для записи, но на самом деле ничего не изменяет и, в частности, не обновляет время модификации). Для проверки каталога на возможность чтения используйте ls -- "$0" >/dev/null. Для проверки каталога на возможность исполнения используйте cd -- "$0". Пассивного теста на возможность исполнения обычного файла, на возможность записи каталога или на доступ к большинству нестандартных файлов не существует.

Связанный контент