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

Вопрос или проблема

Существует ли переменная окружения, которую я могу установить, чтобы её могла считывать find (WSL Ubuntu 20.XX LTS), чтобы она никогда не искала пути, которые содержат, например, node_module или .git, когда выполняется поиск?

Или это будет псевдоним или что-то, что мне нужно будет указывать каждый раз, когда я использую команду find с -path и -prune?

В руководстве для моей реализации find (find (GNU findutils) 4.10.0) есть раздел ближе к концу под названием “ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ”, который перечисляет следующее:

ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ
       LANG   Устанавливает значение по умолчанию для переменных интернационализации,
              которые не заданы или равны нулю.

       LC_ALL Если установлено в непустую строку, переопределяет значения
              всех остальных переменных интернационализации.

       LC_COLLATE
              Стандарт POSIX указывает, что эта переменная влияет
              на сопоставление шаблонов, используемое для опции -name.
              GNU find использует библиотечную функцию fnmatch(3), и
              поддержка LC_COLLATE зависит от системной библиотеки.
              Эта переменная также влияет на интерпретацию ответа на -ok;
              в то время как переменная LC_MESSAGES выбирает
              фактический шаблон, используемый для интерпретации ответа на
              -ok, интерпретация любых выражений в квадратных скобках в
              шаблоне будет зависеть от LC_COLLATE.

       LC_CTYPE
              Эта переменная влияет на обработку классов символов,
              используемых в регулярных выражениях, а также с тестом -name,
              если системная библиотечная функция fnmatch(3) поддерживает
              это. Эта переменная также влияет на интерпретацию любых классов
              символов в регулярных выражениях, используемых для интерпретации ответа на
              подсказку, выданную -ok. Переменная окружения LC_CTYPE также будет
              влиять на то, какие символы считаются невидимыми, когда
              выводятся имена файлов; смотрите раздел НУЖДЫЕ ИМЕНА ФАЙЛОВ.

       LC_MESSAGES
              Определяет локаль, которая будет использоваться для интернационализированных
              сообщений. Если переменная окружения POSIXLY_CORRECT
              установлена, это также определяет интерпретацию ответа на
              подсказку, сделанную действием -ok.

       NLSPATH
              Определяет местоположение каталогов сообщений интернационализации.

       PATH   Влияет на директории, которые ищутся для нахождения
              исполняемых файлов, вызываемых -exec, -execdir, -ok и -okdir.

       POSIXLY_CORRECT
              Определяет размер блока, используемого для -ls и -fls. Если
              POSIXLY_CORRECT установлено, блоки имеют размер 512 байт.
              В противном случае они имеют размер 1024 байта.

              Установка этой переменной также отключает сообщения об ошибках
              (то есть подразумевает -nowarn) по умолчанию, потому что POSIX
              требует, чтобы, кроме вывода для -ok, все
              сообщения, печатаемые в stderr, были диагностическими и
              должны приводить к ненулевому коду завершения.

              Когда POSIXLY_CORRECT не установлено, -perm +zzz
              обрабатывается так же, как -perm /zzz, если +zzz не является
              допустимым символическим режимом. Когда POSIXLY_CORRECT установлено, такие конструкции
              обрабатываются как ошибка.

              Когда POSIXLY_CORRECT установлено, ответ на подсказку,
              сделанную действием -ok, интерпретируется в соответствии с
              каталогом сообщений системы, в отличие от собственных
              переводов сообщений find.

       TZ     Влияет на часовой пояс, используемый для некоторых
              директив формата, связанных со временем, в -printf и -fprintf.

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

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

find обычно считывает содержимое каталогов, используя стандартную функцию readdir() из C-библиотеки, и динамический компоновщик действительно запрашивает переменную окружения $LD_PRELOAD (по крайней мере, на системах GNU) для списка других разделяемых объектов, которые нужно загрузить, с помощью которых вы можете переопределять функции из этих подключенных библиотек.

Если вы создадите файл hide-git.c со следующим содержимым:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>

struct dirent *readdir(DIR *dirp)
{
  static struct dirent* (*orig) (DIR*);
  struct dirent *entp;

  if (!orig)
    orig = (struct dirent* (*) (DIR*)) dlsym (RTLD_NEXT, "readdir");
  if (!orig) abort();
  do {
    entp = (*orig)(dirp);
  } while (entp && strcmp(entp->d_name, ".git") == 0);
  return entp;
}

и скомпилируете его как:

cc -Wall -fPIC -shared -o hide-git.so hide-git.c -ldl

А затем выполните:

export LD_PRELOAD=/path/to/that/hide-git.so

Тогда запись .git (любой файл с именем .git, независимо от того, является ли он каталогом или нет) будет скрыта из результатов readdir() и всего, что использует его для получения содержимого каталогов.

Пример:

$ mkdir -p {.git,.foo,bar}/{1..3}
$ ls -A
bar/  .foo/  .git/
$ find .
.
./.git
./.git/1
./.git/2
./.git/3
./.foo
./.foo/1
./.foo/2
./.foo/3
./bar
./bar/1
./bar/2
./bar/3
$ export LD_PRELOAD=~/hide-git.so
$ ls -A
bar/  .foo/
$ find .
.
./.foo
./.foo/1
./.foo/2
./.foo/3
./bar
./bar/1
./bar/2
./bar/3

Без использования этих трюков, вы всегда можете сделать:

find . '(' -name .git -prune ')' -o '(' ... ')' -print

Вместо:

find ...

.

Ответ или решение

Вопрос использования переменных окружения для управления поведением команды find в Linux, в частности в WSL Ubuntu 20.XX LTS, достаточно интересен и требует понимания особенностей самой команды, а также доступных механизмов модификации ее поведения.

Использование переменных окружения

Как указано в вашем описании, документация для вашего экземпляра find (GNU findutils 4.10.0) не упоминает переменные окружения, которые могут использоваться для исключения из поиска конкретных путей, таких как node_modules или .git. Таким образом, можно concluir, что в данной версии find нет встроенной возможности конфигурирования поведения команды с помощью переменных окружения.

Альтернативные методы исключения путей

  1. Создание алиаса: Один из простейших способов избежать поиска в определенных каталогах — это создать алиас для команды find, который будет включать нужные параметры. Например, вы можете добавить что-то подобное в ваш файл .bashrc:

    alias find='find . \( -path "./node_modules" -o -path "./.git" \) -prune -o -print'

    После добавления запись в .bashrc, не забудьте выполнить команду source ~/.bashrc, чтобы обновить терминал.

  2. Использование опций -path и -prune: Если вы хотите запускать команду find без создания алиаса, то вы можете использовать параметры -path и -prune непосредственно в команде. Вот пример:

    find . \( -path "./node_modules" -o -path "./.git" \) -prune -o -print

    Этот метод позволяет вам гибко настраивать поиск без необходимости создания алиасов.

Продвинутый метод через LD_PRELOAD

Как вы упомянули, можно воспользоваться механизмом LD_PRELOAD, чтобы скрыть определенные директории из результата выполнения команды readdir, который используют многие команды, включая find.

Примерный процесс будет следующим:

  1. Создайте файл hide-git.c с содержимым:

    #define _GNU_SOURCE
    #include <dlfcn.h>
    #include <dirent.h>
    #include <string.h>
    #include <stdlib.h>
    
    struct dirent *readdir(DIR *dirp) {
       static struct dirent* (*orig) (DIR*);
       struct dirent *entp;
    
       if (!orig)
           orig = (struct dirent* (*) (DIR*)) dlsym (RTLD_NEXT, "readdir");
    
       if (!orig) abort(); // Проверка на наличие оригинальной функции
       do {
           entp = (*orig)(dirp); // Получаем следующую запись
       } while (entp && strcmp(entp->d_name, ".git") == 0); // Пропускаем .git
       return entp; // Возвращаем следующий элемент
    }
  2. Скомпилируйте код:

    cc -Wall -fPIC -shared -o hide-git.so hide-git.c -ldl
  3. Установите переменную окружения LD_PRELOAD:

    export LD_PRELOAD=/path/to/hide-git.so

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

Заключение

Таким образом, хотя в GNU find на вашей системе нет встроенной поддержки переменных окружения для исключения путей из поиска, существует несколько эффективных методов, чтобы решить эту задачу. Использование алиасов и параметров -path и -prune — наиболее простые и интуитивно понятные способы. В то время как продвинутые методы, такие как использование LD_PRELOAD, предлагали бы большую гибкость, но требуют больше усилий и технической подготовки.

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

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

Капча загружается...