Как найти все файлы одного владельца

Практические примеры, которые приведены в этой статье, помогут вам освоить очень эффективную и крайне полезную команду find.

Она используется для поиска файлов и папок через командную строку Linux.

Команда find — одна из самых мощных и широко применимых команд. При этом она крайне объёмная и насчитывает более 50 опций, в которых легко запутаться, особенно в сочетании с командами exec или xargs.

Если вы сисадмин или разработчик, избежать команды find при работе с командной строкой не получится. Так что давайте научимся её не бояться и пользоваться её возможностями в полной мере.

Для этого разберём самые распространённые случаи практического применения команды find. Но для начала покажу вам синтаксис и принцип работы с командой.

Команда find в Linux

Общий синтаксис команды find выглядит так:

find [directory to search] [options] [expression]

Всё, что в квадратных скобках, указывать необязательно. А значит, выполнить команду find можно вообще без опций и параметров. Она выдаст список всех файлов и папок в текущем расположении. Мало полезного, да?

Так что давайте взглянем на параметры подробнее:

  • directory to search (папка поиска) — это расположение, с которого вы хотите начать поиск. Поиск по умолчанию рекурсивный и начинается с текущего расположения.
  • options (опции) содержит указание типа поиска: по имени, типу файла, времени изменения и так далее — тут может быть более 50 вариантов.
  • expression (выражение) содержит поисковый запрос. Если вы ищете файл по имени, параметр expression должен содержать имя файла. Если ищете файлы с именем, соответствующим заданному шаблону, поисковое выражение — это шаблон.

Приведу простой пример:

find . -type f -name myfile

Такая команда выполнит поиск файла (именно файла, не папки) с именем myfile в текущей папке и подпапках. Опция -type f сужает поиск до файлов. Точка (.) указывает на текущую папку.

Рассмотрим несколько примеров применения команды find.

Поиск файлов и папок по имени

Так выполняется поиск файлов и папок по имени:

find . -name SEARCH_NAME

Поскольку тип объекта не указан, команда выполняет поиск и файлов, и папок.

Пример ниже — поиск файлов и папок с именем «mystuff»:

abhishek@LHB:~/Examples$ find -name mystuff
./new/mystuff
./mystuff

Поиск только файлов или только папок

Если нужно искать только файлы, на помощь придёт опция type -f:

find . -type f -name SEARCH_NAME

Тип и имя можно указывать в любом порядке. Возьмём пример выше и ограничим круг поиска файлами:

abhishek@LHB:~/Examples$ find -type f -name mystuff
./mystuff

Если нужно найти папку, укажите тип type -d:

find . -type d -name SEARCH_NAME

Вот пример нашего поиска уже по папкам:

abhishek@LHB:~/Examples$ find -type d -name mystuff
./new/mystuff

Поиск без учёта регистра

Команда find по умолчанию учитывает регистр. Чтобы выполнить поиск по имени файла без учёта регистра, надо ввести опцию -iname вместо -name.

find . -type f -iname SEARCH_NAME

С поиском по папкам (type -d) это тоже работает.

abhishek@LHB:~/Examples$ find -iname mystuff
./new/mystuff
./MyStuff
./mystuff

Скриншот последних трёх примеров:

image

Поиск файлов по расширению (важно)

Одно из самых популярных применений команды find — поиск файлов определённого типа, то есть по заданному расширению.

Скажем, вы хотите найти все файлы С++ в текущих папках. Файлы С++ имеют расширение .cpp, и вот как их можно найти:

find . -type f -name "*.cpp"

С такими опциями команда find найдёт только файлы (-type f) с именами, оканчивающимися на .cpp.

abhishek@LHB:~$ find . -type f -name "*.cpp"
./file.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream2/zstream_test.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream/test.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream/zfstream.cpp

При работе с командой find всегда заключайте поисковое выражение в двойные кавычки.

С чем связана рекомендация заключать поисковый запрос в двойные или одинарные кавычки? Дело в том, что без кавычек оболочка будет работать с символом * как с джокером и выполнит подстановку.

Вот что будет, если ввести запрос без кавычек:

find . -type f -name *.cpp

Оболочка распознает подстановочный знак * и заменит его всеми файлами в текущей папке, чьи имена заканчиваются на .cpp.

Это сработает, если такой файл всего один, но если их несколько, оболочка пожалуется на некорректный синтаксис.

image

В нашем случае файл .cpp всего один, и после подстановки команда выглядит так: find . -type f -name file.cpp. Она работает, поскольку file.cpp — корректный поисковый запрос.

А вот файлов .txt в той же папке два, и когда команда расширяется до find . -type f -name another.txt new.txt, выводится предупреждение, потому что поисковых запросов больше одного.

Именно поэтому сам поисковый запрос всегда следует заключать в двойные кавычки.

Поиск нескольких файлов с несколькими расширениями (или условием)

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

Вместо того чтобы прогонять команду find несколько раз, введите её один раз с опцией -o, которая работает как логическое условие «или»:

find . -type f -name "*.cpp" -o -name "*.txt" 

Например:

abhishek@LHB:~/Examples$ find . -type f -name "*.txt" -o -name "*.cpp"
./new.txt
./file.cpp
./new/new.txt
./new/dir2/another.txt
./new/dir1/new.txt
./another.txt

Поиск файлов в заданной папке

Все приведённые примеры иллюстрируют поиск в текущей папке, потому что команда включает в себя точку (.).

Чтобы выполнить поиск в заданной папке, не покидая текущего расположения, можно заменить точку абсолютным или относительным путём к нужной папке.

abhishek@LHB:~/Examples$ find ./new -name mystuff
./new/mystuff

Поиск файлов в нескольких папках

Если нужные вам файлы могут находиться в нескольких папках, можно выполнить поиск во всех этих расположениях за один раз. Просто укажите все пути к папкам при введении команды find:

find ./location1 /second/location -type f -name "pattern"

Поиск пустых файлов и папок

Опция -empty позволяет использовать команду find для поиска пустых файлов и папок.

Найти таковые в текущей папке можно следующим образом:

find . -empty

Можно указать тип объектов, чтобы искать только файлы или только папки:

find . -empty -type f

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

find . -empty -type f -name "*.cpp"

image

Поиск крупных и мелких файлов (поиск по размеру файла)

Команда find поможет найти крупные или мелкие файлы, если выполнить поиск по размеру. Но это работает только для файлов, не для папок.

Используется опция -size с аргументом +N для файлов размером более N и -N для файлов размером менее N.

А вот как можно найти файлы точного заданного размера (50 КБ):

find . -size 50k

Так выполняется поиск файлов размером более 1 ГБ в текущей папке:

find . -size +1G

А так — файлов, не превышающих 20 байт:

find . -size -20c

Для поиска файлов размером более 100 МБ, но менее 2ГБ, введите:

find . -size +100M -size -2G

Поиск по размеру тоже можно сочетать с поиском по имени файла. Таким образом, найти в корневом каталоге все файлы размером более 500 МБ с именем, оканчивающимся на .log, можно так:

find / -size +500M -name "*.log"

Для справки:

  • c – байты
  • k – килобайты
  • M – мегабайты
  • G – гигабайты

Поиск недавно изменённых файлов (поиск по времени изменения или создания)

Вы ведь знакомы с параметрами mtime, atime и ctime?

  • Mtime – время последнего изменения файла
  • Ctime – время создания файла
  • Atime – время последнего доступа к файлу

Вы не раз столкнётесь с ситуацией, когда нужен список всех недавно изменённых файлов. В таких случаях на помощь приходит поиск по времени изменения.

Найти все файлы, претерпевшие изменения за последние трое суток (3*24ч), можно так:

find . -type f -mtime -3

А все файлы, созданные пять и более дней назад, ищутся так:

find . -type f -ctime +5

Понимаю, что 24 часа — большой срок. Что если нужно выявить файлы, изменённые всего пару минут назад? Для этого предусмотрены опции mmin, amin и cmin.

Так выглядит команда поиска всех файлов, изменённых за последние пять минут:

find . -type f -mmin -5

image

Можно не только указать имя файла, но и ограничить временной промежуток с двух сторон. Команда ниже выполнит поиск всех файлов .java, изменённых не ранее 30 и не позднее 20 минут назад.

find . -type f -mmin +20 -mmin -30 -name "*.java"

Поиск файлов с определёнными настройками доступа

Надеюсь, вы имеете представление о разрешениях файлов в Linux.

Команда find позволяет выполнить поиск файлов по разрешению и режиму доступа.

find -perm mode

Поищем в текущей папке, к примеру, все файлы с режимом доступа 777:

find . -perm 777

А так можно найти все файлы с правами на чтение и запись для всех типов пользователей (только точное совпадение; файлы с правами на выполнение для всех не отобразятся):

find . -perm a=r+w

Поиск файлов по владельцу

Можно также найти файлы, принадлежащие определённому пользователю.

Вот как обнаружить в текущей папке все файлы пользователя Джона:

find . -type f -user John

Эта опция сочетается с другими, будь то размер или время и имя файла:

find . -type f -user John -name "*.cpp"

Отключение рекурсивного поиска для поиска только в текущей папке

По умолчанию команда find выполняет поиск во всех подпапках текущего расположения. Если это не требуется, можно ограничить глубину поиска значением «1». Так вы ограничитесь поиском в текущей папке, не залезая в подпапки.

find . -maxdepth 1 -type f -name "*.txt"

image

Исключение папки из поиска

Если нет необходимости производить поиск в той или иной папке, можно исключить её с помощью опций path, prune и логического «или».

find . -path "./directory_exclude/*" -prune -o -name SEARCH_NAME

Будьте внимательны: путь к папке должен оканчиваться на *, затем идёт -prune и только потом -o.

Попросту говоря, при поиске с опцией prune папка, указанная с помощью path, игнорируется. Prune всегда сопровождается флагом -o (логическое «или»), чтобы папки, которые не были исключены, просматривались на наличие искомого объекта.

Дальнейшая работа с результатами команды find: exec и xargs

Итак, мы изучили различные способы поиска файлов по заданным параметрам. Это хорошо. А теперь следующий шаг: рассмотрим, какие действия можно выполнять с результатами команды find.

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

Вам уже известно, что в Linux можно использовать перенаправление ввода-вывода, чтобы объединить результаты одной команды с вводом другой. Но с результатами команды find это не сработает — по крайней мере, не напрямую.

Чтобы выполнить действия над результатом команды find, есть два варианта:

  • Применить exec
  • Применить xargs

Использование find и exec

Допустим, вам нужен подробный список (ls -l) файлов, найденных командой find. Вот как его получить:

find . -type f -name "*.txt" -exec ls -l {} +

Результат будет таким:

abhishek@LHB:~/Examples$ find . -type f -name "*.txt" -exec ls -l {} +
-rw-rw-r-- 1 abhishek abhishek 39 Oct 13 19:30 ./another.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 15:36 ./new/dir1/new.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 15:36 ./new/dir2/another.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 18:51 ./new/mystuff/new.txt
-rwxrwxrwx 1 abhishek abhishek 35 Oct 13 15:37 ./new/new.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 18:16 ./new.txt

Многие забывают ввести {} + в конце команды exec. Но это необходимо — как и пробел между скобками {} и плюсом +.

Фигурные скобки ссылаются на результат выполнения команды find. Их содержимое может иметь следующий вид: {файл 1, файл 2, файл 3}. Символ + используется как конец команды exec.

Есть ещё один вариант оформления exec:

find . -type f -name "*.txt" -exec ls -l {} ;

В данном случае плюс заменён на точку с запятой. Дополнительная косая черта означает, что точка с запятой не является специальным символом.

Преимущество сочетания {} + заключается в меньшем количестве команд ( ls -l file1 file2 file3), тогда как комбинация {} ; запустит цепочку ls -l file1, ls -l file2 и так далее.

Однако сочетание {} ; даёт возможность использовать {} несколько раз в одном и том же выражении exec. Так, приведённая ниже команда переименует все обнаруженные файлы с расширением .old.

find . -type f -name "*.txt" -exec mv {} {}.old ;

Использование команды xargs

Многие пользователи Linux сталкиваются с необходимостью перенаправления ввода-вывода довольно часто. Но команда exec с цепочкой символов {} + кажется им слишком сложной.

И тут на помощь приходит xargs. Нужно просто перенаправить вывод команды find в команду xargs через конвейер.

find . -type f -name "*.txt" | xargs ls -l

image

Синтаксис куда проще, верно? К тому же команда xargs тоже весьма эффективна. Подробнее о ней — в статье по ссылке.

Сочетание команд find и grep

Теперь вы умеете совмещать команду find с xargs и exec, и пора перейти на следующий уровень — объединить find и grep.

Для сисадминов и разработчиков комбинация команд find и grep — одна из самых распространённых и вместе с тем самых полезных.

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

Например, вам нужно найти все файлы .txt, в которых есть имя «Alice». Объединить команды find и grep можно так:

find . -type f -name "*.txt" -exec grep -i alice {} +

А можно с помощью xargs:

find . -type f -name "*.txt" | xargs grep -i alice

image

Конечно, пример элементарный, но если команда grep вам знакома, можете использовать её на своё усмотрение.

И это далеко не все возможности команды find…

Перечислить все опции и примеры использования команды find практически невозможно. Её возможностям нет границ, но если вы освоите её принципы, она окажется очень кстати во многих ситуациях. Решающий фактор — как сочетается логика действия разных опций и команд.

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


НЛО прилетело и оставило здесь промокоды для читателей нашего блога:

— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

— 20% на выделенные серверы AMD Ryzen и Intel Core — HABRFIRSTDEDIC.

Доступно до 31 декабря 2021 г.

  • Remove From My Forums

 locked

Поиск файлов по владельцу

  • Вопрос

  • Добрый день, помогите облегчить жизнь начинающему системному администратору. Необходимо найти файлы на файловом сервере по владельцу. То есть указать пользователя и файлы. Нашел скрипт он ищет только файлы с расширением
    *.txt и во всем компьютере, мне нужно на конкретно в расшаренной папке

    Get-ChildItem *.txt | Format-Table -Property name, @{Label = “Owner”; expression = {$_.GetAccessControl().owner}}

Ответы

  • Не помню точно, достаточно ли для выполнения этой команды установленной FSRM или отдельно квоты на диск надо включать. Имхо тут есть некоторое преимущество перед 

    Нужно включать дисковые квоты (те, которые в свойствах диска, не FSRM).


    Слава России!

    • Предложено в качестве ответа

      22 апреля 2017 г. 10:51

    • Помечено в качестве ответа
      Vector BCO
      22 апреля 2017 г. 10:51

  • кстати именно про поиск по оунеру…

    проверьте следующее…

    fsutil file findbysid domainuser C:myshare
    где соответственно:domainuser – пользователель

    C:myshare – путь до вашей папки с шарой

    Не помню точно, достаточно ли для выполнения этой команды установленной FSRM или отдельно квоты на диск надо включать. Имхо тут есть некоторое преимущество перед 

    Get-ChildItem c:konkretnayaPapka 

    т.к. бежим не по каталогу, а вродь как должны шариться по дескрипторам в mft в режиме игнора пермишенов.

    • Предложено в качестве ответа
      Vector BCO
      22 апреля 2017 г. 10:51
    • Помечено в качестве ответа
      Vector BCO
      22 апреля 2017 г. 10:51

  • Get-ChildItem c:konkretnayaPapka -recurse | Select FullName, @{Label = "Owner"; expression = {$_.GetAccessControl().owner}} 

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

    Get-ChildItem c:konkretnayaPapka -recurse | `

    Select FullName, @{Label = "Owner"; expression = {$_.GetAccessControl().owner}} | `

    where {$_.Owner -eq 'DomainUserName'} | ft Owner, FullName -autosize


    The opinion expressed by me is not an official position of Microsoft

    • Изменено
      Vector BCO
      18 апреля 2017 г. 6:09
    • Предложено в качестве ответа
      Vector BCO
      22 апреля 2017 г. 10:50
    • Помечено в качестве ответа
      Vector BCO
      22 апреля 2017 г. 10:51

  • Get-ChildItem “C:test” -file –Recurse
    | Format-Table -Property name, @{Label = “Owner”; expression = {$_.GetAccessControl().owner}}

    • Помечено в качестве ответа
      Vector BCO
      22 апреля 2017 г. 10:51

Перейти к содержанию

🐧 Как найти все файлы, принадлежащие определенному пользователю в Unix / Linux

На чтение 1 мин Опубликовано 25.08.2020

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

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

Чтобы найти все файлы на сервере, принадлежащем этому пользователю, выполните следующую команду.

find / -user $USERNAME 

Замените $USERNAME фактическим именем пользователя, которому принадлежат искомые файлы.

Эта команда будет искать файлы, принадлежащие конкретному пользователю, во всей файловой системе.

Так что на это уйдет много времени.

Рекомендуется сохранить вывод в файлы вместо отображения на терминале.

find / -user $USERNAME > user-files.txt

Все файлы, принадлежащие данному пользователю, будут сохранены в файле user-files.txt.

Пожалуйста, не спамьте и никого не оскорбляйте.

Это поле для комментариев, а не спамбокс.

Рекламные ссылки не индексируются!

Иногда для оптимизации управления хранением данных на диске администратору требуется узнать, какие файлы принадлежат пользователю и сколько места на диске они занимают. Эту информацию нельзя получить из пользовательского графического интерфейса Windows или с помощью сценария Windows. Я написал библиотеку ActiveX DLL и сценарий VBScript, который выводит список файлов, принадлежащих определенному владельцу, а также размеры этих файлов

Получение информации, не предоставляемой средством квотирования дисков в Windows

.

Ограничения функции квотирования диска

В Windows 2000 и более поздних версиях имеется функция квотирования диска, которую можно использовать для отслеживания или ограничения работы с диском NTFS. Для просмотра или настройки квотирования диска нужно щелкнуть правой кнопкой мыши на выбранном диске в Windows Explorer, выбрать пункт Properties, и перейти на закладку Quota.

Щелкните на кнопке Quota Entries, чтобы увидеть список пользователей и объем занимаемого каждым из них дискового пространства. Эта информация берется из сведений о владельце в файлах NTFS. Диалоговое окно Quota Entries позволяет переопределить записи квот, установленные по умолчанию, последовательно (один пользователь за другим), добавлять и удалять записи квот и даже импортировать и экспортировать их. К сожалению, настраивать записи квот на основе групп невозможно, а функция квотирования может быть разрешена или запрещена только для томов. Однако даже с этими ограничениями функция квотирования диска может быть полезной.

Окно Quota Entries отображает список владельцев файлов и объем используемого ими дискового пространства, но операционная система не предоставляет способ получения списка файлов, принадлежащих пользователю, если только не щелкнуть правой кнопкой мыши на записи пользователя, не выбрать пункт Delete, а потом Yes. Если пользователь имеет файлы на данном томе, Windows отобразит диалоговое окно, которое позволит удалить или присвоить себе право владения файлами пользователя. В этом окне отображаются файлы, принадлежащие пользователю, но не показано занимаемое ими дисковое пространство. Также нет возможности экспортировать список файлов в новый файл для отчетности. Это ограничение может вызвать проблемы, если пользователи начнут превышать объем имеющегося дискового пространства.

Чтобы решить задачу построения списка файлов и дискового пространства для данного владельца файлов, я решил написать сценарий. Сценарии Windows не позволяют получить имя владельца файла, и хотя существует возможность узнать имя владельца файла с помощью средств Windows Management Instrumentation (WMI), я решил отказаться от нее из соображений сохранения производительности. Вместо этого я создал библиотеку ActiveX DLL GetOwner.dll, которая возвращает имя владельца файла. Еще я написал сценарий OwnedBy.vbs на VBScript, использующий библиотеку DLL для вывода неограниченного списка файлов, принадлежащих определенному пользователю, их размеров и содержащих их папок. Можно настроить вывод списка в файл для дальнейшего анализа и при необходимости импортировать его в электронную таблицу или базу данных.

Можно загрузить файлы GetOwner.dll, OwnedBy.vbs и исходный код библиотеки DLL с сайта Windows IT Pro/RE (ссылка на файл 46487.zip). Некоторые читатели не смогут воспользоваться библиотекой DLL, даже при наличии исходного кода. Для них я написал версию файла OwnedBy.vbs, которая использует файл ADsSecurity.dll из набора разработчика программного обеспечения (SDK) для Active Directory Service Interfaces (ADSI). Однако, по возможности, я рекомендую задействовать библиотеку GetOwner.dll, для сохранения производительности: судя по моим тестам, данный вариант работает почти в 9 раз быстрее.

Требования сценария

Для работы OwnedBy.vbs под Windows 2000 необходим пакет VBScript 5.6. Это требование можно удовлетворить, установив пакет Microsoft Internet Explorer (IE) 6.0. В системах Windows Server 2003 и Windows XP пакет VBScript 5.6 является частью операционной системы.

Сценарий также требует регистрации библиотеки GetOwner.dll на локальном компьютере. Для этого нужно скопировать файл GetOwner.dll в папку (например, %systemroot%system32) и ввести в командной строке следующую команду:

regsvr32 [/s] pathgetowner.dll

где path – путь к файлу getowner.dll. Параметр /s (silent) отключает появление диалогового окна с подтверждением. Чтобы удалить библиотеку DLL из реестра, следует добавить параметр /u после команды regsvr32. Для удаления без подтверждения нужно одновременно использовать параметры /u и /s. Чтобы иметь возможность удалять и добавлять библиотеки DLL в реестр, пользователь должен быть членом локальной группы Administrators.

Для компиляции библиотеки GetOwner.dll я использовал пакет Visual Basic (VB) 6.0. Рабочий модуль VB (msvbvm60.dll) устанавливается по умолчанию вместе с системой Windows 2000 и более поздними версиями.

Использование сценария OwnedBy.vbs

Из-за того, что сценарий OwnedBy.vbs использует для вывода окно команд, он должен исполняться с применением хоста CScript. Для настройки CScript в качестве хоста по умолчанию для текущего пользователя нужно ввести в командную строку следующую команду:

cscript //h:cscript //nologo //s

Сценарий OwnedBy.vbs использует следующий синтаксис командной строки:

[cscript] ownedby.vbs 
[/s] [/d:char]
[/o:owner] [/nh] [/ns]

Ключевое слово cscript требуется только в том случае, если узел CScript не является хостом сценария по умолчанию. Другие параметры командной строки могут присутствовать всегда.

Необходимо указать одно или несколько имен папок вместо параметра . Если имя папки содержит пробелы, его следует заключить в кавычки. Если требуется получить информацию по файлам в подкаталогах, добавьте параметр /s. Сценарий выдает выходные данные в форме столбцов. По умолчанию в выходных данных столбцы отделяются друг от друга символом табуляции. Чтобы указать другой разделительный символ, используйте параметр /d, сопровождаемый символом «;», например ключ /d:; позволяет вывести список, разделяемый символом «;».

Можно указать, что в списке должны отображаться только файлы, принадлежащие определенному пользователю. Для этого нужно ввести ключ /o и заменить параметр owner именем пользователя в формате «доменимя пользователя». Если не указать имя домена, используется текущий домен (тот, в котором вы регистрировались). Если не указать ключ /o, сценарий OwnedBy.vbs включает в список файлы, принадлежащие каждому из пользователей.

По умолчанию сценарий OwnedBy.vbs выводит строку заголовка, описывающую каждый столбец (то есть Owner, ParentFolder, Name, Size). Надписи заголовка могут пригодиться при импортировании отчета в электронную таблицу или базу данных, но если вы не хотите, чтобы сценарий выводил строку заголовка, используйте ключ /nh.

В конце сценарий выводит итоговую строку вида

n byte(s) in x file(s)

где n – суммарный размер файлов, x – число найденных файлов. Чтобы отключить вывод итоговой строки, используйте ключ /ns.

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

ownedby.vbs d: /o:corpsmithj
/s > d:smithj.txt

добавляет в список все файлы на диске D, принадлежащие пользователю corpsmithj, и сохраняет отчет в файле d:smithj.txt. Если сценарий сталкивается с ошибкой чтения файла или каталога, он прописывает сведения об ошибке в стандартное сообщение, определенное по умолчанию в окне команд. Можно перенаправить вывод стандартного сообщения об ошибке в файл, например

ownedby.vbs d: /o:corpsmithj
/s > d:smithj.txt
2> d:errors.log

Эта команда пересылает только сообщения об ошибках в файл d:errors.log.

Вы также можете направить стандартный вывод и вывод стандартного сообщения об ошибке в один и тот же файл, например

ownedby.vbs d: /o:corpsmithj
/s > d:smithj.txt 2>&1

Эта команда сохраняет и стандартный вывод, и стандартные сообщения об ошибках в файле d:smithj.txt. Нужно иметь в виду, что если запустить сценарий OwnedBy.vbs для целого тома, он, возможно, выдаст объем используемого дискового пространства, несколько заниженный по сравнению с результатами в окне Quota Entries. Это происходит в силу завышения объемов файловой системой NTFS.

Подпрограмма Main

Подпрограмма Main сценария OwnedBy.vbs, показанная в Листинге 1, сначала объявляет свои переменные, а затем проверяет наличие аргументов командной строки. Если в командной строке присутствует параметр /? или отсутствуют имена папок, сценарий вызывает подпрограмму Usage, которая отображает краткое сообщение об использовании сценария и заканчивает работу.

Затем сценарий вызывает функцию ScriptHost(), чтобы определить, какой исполнитель работает со сценарием. Если это не CScript, сценарий вызывает подпрограмму Die для завершения работы сценария с сообщением об ошибке и кодом выхода, отличным от нуля.

Если сценарий OwnedBy.vbs исполняет CScript, подпрограмма Main пытается создать экземпляр объекта ListByOwner. Так как описание класса для объекта ListByOwner существует в файле сценария OwnedBy.vbs, подпрограмма использует ключевое слово New оболочки VBScript вместо метода CreateObject оболочки WScript. Если сценарий OwnedBy.vbs не может создать объект ListByOwner, он заканчивает работу с сообщением об ошибке.

Если объект ListByOwner успешно создается, сценарий проверяет наличие аргументов командной строки /o, /d, /s, /nh и /ns. Аргументы /o, /d и /s соответствуют свойствам объекта ListByOwner – Owner, Delim и Recurse. Я вкратце остановлюсь на них. Булевы переменные blnHeader и blnSummary устанавливаются в значение False, если параметры /nh и /ns, соответственно, присутствуют в командной строке.

Если переменная blnHeader имеет значение True (то есть ключ /nh отсутствует в командной строке), сценарий выполняет метод OutputHeader объекта ListByOwner. Далее сценарий отключает установленный по умолчанию обработчик ошибок VBScript с помощью выражения On Error Resume Next и переходит к перебору аргументов командной строки (то есть имен папок) с помощью цикла For Each.

В теле цикла For Each сценарий устанавливает свойство Folder объекта ListByOwner в соответствии с аргументом командной строки. Если объект ListByOwner вызывает ошибку (например, если папка не существует), сценарий прописывает сообщение об ошибке в стандартное сообщение об ошибке; если нет – сценарий вызывает метод Run объекта ListByOwner. Последним шагом подпрограммы Main является проверка переменной blnSummary. Если значение – True (то есть параметр /ns отсутствует в командной строке), сценарий вызывает метод OutputSummary объекта ListByOwner.

Работа с объектом ListByOwner

Работа сценария OwnedBy.vbs выполняется с помощью объекта ListByOwner. Свойства, используемые объектом ListByOwner, как и частные переменные, применяемые каждым свойством, приведены в Таблице 1. Методы объекта ListByOwner приведены в Таблице 2.

Когда сценарий создает экземпляр объекта ListByOwner с помощью ключевого слова New среды VBScript, автоматически вызывается процедура события Class_Initialize, для инициализации частных переменных объекта и выполнения других задач, возникающих при создании объекта.

Первое, что пытается сделать объект ListByOwner, это создать экземпляр объекта GetOwner.Owner. Это действие не может быть выполнено, если файл библиотеки GetOwner.dll не зарегистрирован в системе. Код процедуры события выполняет собственную обработку ошибки – если метод CreateObject вызывает ошибку, объект ListByOwner вызывает собственную ошибку, вместо отмены выполнения всего сценария. Подпрограмма Main перехватывает эту ошибку и заканчивает работу в штатном режиме.

Затем процедура события Class_Initialize создает частный указатель на объект Scripting.FileSystemObject и устанавливает для свойств значения по умолчанию. После завершения процедуры Class_Initialize переменная objLBO подпрограммы Main содержит инициализированный объект ListByOwner.

Установка свойства Folder

Выражения Public Property Let, которые являются частью языка VBScript, определяют процедуры свойств, которые выполняют управление свойствами объекта ListByOwner. Каждая из процедур свойств устанавливает соответствующую частную переменную, как показано в Таблице 1. При установке свойства Folder код выполняет собственную обработку ошибки и вызывает ошибку, если метод GetFolder объекта FileSystem-Object не может быть выполнен. В этом случае подпрограмма Main может обнаружить ошибку в штатном режиме и перейти к следующей папке, указанной в командной строке.

Подпрограмма ProcessFolder

Когда подпрограмма Main вызывает метод Run объекта ListByOwner, он выполняет подпрограмму ProcessFolder с частной переменной objFolder в качестве аргумента. Подпрограмма ProcessFolder выполняет работу по перебору множеств файлов и папок.

Подпрограмма ProcessFolder выполняет собственную обработку ошибок. Она отключает установленный по умолчанию обработчик ошибок VBScript с помощью выражения On Error Resume Next. Потом, если частная переменная blnRecurse имеет значение True, подпрограмма перебирает множество подкаталогов исходной папки с помощью цикла For Each и вызывает сама себя для каждого подкаталога.

Далее подпрограмма перебирает множество файлов и папок с помощью цикла For Each. Имя владельца каждого файла мы получаем с помощью вызова метода GetOwner объекта objGetOwner, который возвращает строку, содержащую имя владельца файла в виде доменимя пользователя. Если свойство Owner объекта ListByOwner содержит пустую строку (например, конкретный пользователь не указан) или совпадает с именем владельца текущего файла, тогда подпрограмма выводит информацию о файле в следующем виде:

Owner ParentFolder Name Size

В конце подпрограмма ProcessFolder обновляет внутренние переменные объекта ListByOwner, содержащие общее количество файлов и их суммарный размер. Нужно иметь в виду, что вывод без ошибок направляется на стандартный вывод, а вывод с ошибками – на стандартный вывод сообщений об ошибках.

Дополнение к средству квотирования диска

Функция квотирования дисков в Windows полезна, но она недостаточно мощная. Библиотека GetOwner.dll в связке со сценарием OwnedBy.vbs снимает ограничения квотирования, позволяя искать все файлы, принадлежащие пользователю, в одной или нескольких папках и получать сведения об их размерах. Даже если квотирование не используется, эта библиотека DLL и сценарий помогут администратору управлять дисковым пространством более эффективно.


Листинг 1. Подпрограмма Main
Sub Main
' BEGIN COMMENT
' Переменная objLBO содержит указатель на объект ListByOwner.
' END COMMENT
 Dim objLBO, blnHeader, blnSummary, strFolder
' BEGIN COMMENT
 ' Если в командной строке присутствует параметр /? или если отсутствуют имена папок,
 ' выполняется выход с сообщением об использовании.
' END COMMENT
 With WScript.Arguments
 If .Named.Exists(?) Or .Unnamed.Count = 0 Then Usage
 End With
' BEGIN COMMENT
 ' Завершение сценария с сообщением об ошибке, если он не выполняется хостом CScript.
' END COMMENT
 If ScriptHost() <> cscript.exe Then _
 Die You must run this script using the CScript host., 1
' BEGIN COMMENT
 ' Сценарий завершится с ошибкой, если в случае создания экземпляра объекта ListByOwner
 ' выявляется ошибка. Это ошибка часто связано с тем, что библиотека
 ADsSecurity.dll не зарегистрирована.
' END COMMENT
 On Error Resume Next
 Set objLBO = New ListByOwner
 If Err <> 0 Then Die [0x & Hex(Err) & ] & Err.Description, Err
 On Error GoTo 0
 With WScript.Arguments
' BEGIN COMMENT
 ' Получение имени владельца из параметра /O. Если пусто - вывод для всех владельцев.
' END COMMENT
 objLBO.Owner = .Named(O)
' BEGIN COMMENT
 ' Получение разделителя выходных данных.
' END COMMENT
 objLBO.Delim = .Named(D)
' BEGIN COMMENT
 ' Если присутствует параметр /S, выполняется рекурсия в каждом подкаталоге.
' END COMMENT
 objLBO.Recurse = .Named.Exists(S)
' BEGIN COMMENT
 ' Если присутствуют параметры /NH или /NS, выполняется пропуск строки
 заголовка и итоговой строки соответственно.
' END COMMENT
 blnHeader = Not .Named.Exists(NH)
 blnSummary = Not .Named.Exists(NS)
 End With
' BEGIN COMMENT
 ' Вывод строки заголовка (при необходимости).
' END COMMENT
 If blnHeader Then objLBO.OutputHeader
' BEGIN COMMENT
 ' Сценарий будет обрабатывать собственные ошибки в приведенном ниже цикле For Each.
' END COMMENT
 On Error Resume Next
 For Each strFolder In WScript.Arguments.Unnamed
 objLBO.Folder = strFolder
 If Err <> 0 Then
 ' The ListByOwner object raised an error.
 WScript.StdErr.WriteLine [0x & Hex(Err) & : _
 & Err.Description & ] & strFolder
 Else
 objLBO.Run
 End If
 Err.Clear
 Next
' BEGIN COMMENT
 ' Вывод итоговой строки (при необходимости).
' END COMMENT
 If blnSummary Then objLBO.OutputSummary
End Sub

Таблица 1. Свойства и частные переменные объекта ListByOwner
Свойство Описание Частная переменная
Folder Свойство Folder принимает значение, соответствующее имени каждой папки, указанной в командной строке. Если при доступе к папке возникает ошибка (например, папки не существует), объект вызовет ошибку objFolder
Recurse Свойство Recurse устанавливается в значение True, если объект должен обращаться к подкаталогам указанной папки. Значение по умолчанию – False blnRecurse
Owner Свойство Owner принимает значение вида домен/имя пользователя, соответствующее имени пользователя, по которому должен осуществляться поиск. Если имя домена не указано, используется текущий домен. Если это свойство содержит пустую строку (по умолчанию), будут выведены данные по всем владельцам strOwner
Delim Свойство Delim определяет символ, используемый для разделения столбцов на выходе. По умолчанию – символ табуляции strDelim

Таблица 2: Методы объекта ListByOwner
Метод Описание
OutputHeader Метод OutputHeader выводит строку заголовка. Столбцы отделены друг от друга символом, указанным в свойстве Delim
Run Метод Run запускает процесс вывода для папки, указанной в свойстве Folder. Работа управляется частной подпрограммой ProcessFolder
OutputSummary Метод OutputSummary выводит итоговую строку (общий размер в байтах и количество файлов)

Добавить комментарий