Управление специализированными окружениями в Windows

Дата публикации: 2016.02.23

Наверняка все знают, что в операционных системах Windows и Linux есть специальная переменная окружения PATH, которая должна включать в себя список путей к директориям с исполняемыми файлами. Если оболочку просят запустить исполняемый файл без указания абсолютного пути к нему — она осуществит поиск в переменной окружения PATH, иногда с некоторыми модификациями (например, в Windows поиск будет осуществлён с подстановкой расширений файлов из другой переменной окружения, PATHEXT).

Часто с этой переменной окружения приходится работать при использовании консольных приложений или систем сборки. Её можно модифицировать во время выполнения процесса, и дочерние процессы будут наследовать изменённое значение (в общем-то, так работают любые переменные окружения).

В среднем под Windows неправильно настроенный PATH доставляет больше проблем, поскольку выполняемые файлы программ не складываются в какие-то централизованные директории, типа /bin и /usr/bin в FHS, и поэтому каждая программа управляет этим самостоятельно. Разумеется, в результате получается зоопарк: какие-то программы при установке добавляются туда без запроса, какие-то не добавляются, даже если пользователь этого хотел бы, а какие-то могут забыть удалиться из PATH при деинсталляции. В итоге каждому, кто хоть немного работал с консольными программами в Windows, хочется каких-то инструментов и практик для того, чтобы не засорять эту переменную окружения, и упорядочить обращение с ней.

К счастью, есть несколько способов и средств, которые существенно улучшают ситуацию и позволяют практически не заботиться о проблемах, связанных с тем, что кто-нибудь опять испортил переменную окружения PATH.

Откуда берётся PATH

Начнём с основ: откуда же берётся эта переменная окружения изначально?

Как и все переменные окружения, в каждом конкретном процессе она формируется на основании значения из родительского процесса. Главным родителем всех пользовательских процессов является explorer.exe, так что за передачу начального варианта окружения отвечает именно этот процесс.

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

Для редактирования переменных окружения используется стандартная программа SystemPropertiesAdvanced.exe. Стоит отметить, что после редактирования этих настроек уже запущенные процессы не обнаружат изменений своего окружения; более того, не все вновь запущенные процессы будут использовать новый вариант окружения!

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

А каким же тогда образом изменяется окружение в explorer.exe? Дело в том, что он подписывается на глобальное событие WM_SETTINGCHANGE, и автоматически обновляет своё окружение. Пользовательская программа может делать точно так же, если для неё важно перезагружать переменные окружения.

(Я не уверен на 100%, что explorer.exe работает буквально именно таким образом, но во всяком случае система ведёт себя именно так.)

Максимальный размер PATH

В (не таких уж и) старых версиях Windows (вплоть до 7 SP 1 / Server 2008 R2 SP1) имеется достаточно жёсткое ограничение на максимальный размер PATH: это всего 2047 символов (к сожалению, сложно сказать наверняка, в какой мере этот лимит распространяется на пользовательское, системное и комбинированное окружение). Если лимит превышен, то всё становится очень плохо, из PATH теряются записи, а запуск новых программ начинает работать очень ограниченно.

Примечательно, что в условиях сломанной переменной PATH не получается даже запустить SystemPropertiesAdvanced.exe, в том числе и из панели управления, т.к. путь к этой программе там тоже берётся из окружения (которое, напомню, сломано). В общем, лучше такого не допускать :)

Для того, чтобы немного расширить допустимые размеры окружения, есть специальный патч от Microsoft. Он расширяет максимальный размер PATH до 4095 символов.

Я не проверял этот патч на новых версиях Windows; также я не проверял и максимальную длину окружения на них, т.к. начал пользоваться прочими способами управления окружением, перечисленными ниже.

Редактирование окружения

Для редактирования переменных окружения я рекомендую использовать бесплатную программу Rapid Environment Editor. Она особенно хороша тем, что умеет подсвечивать некорректные фрагменты внутри PATH, что позволяет быстро избавиться ссылок на различного рода неправильные или удалённых пути внутри этой переменной.

Установка программ

Выше я упоминал, что многие программы забывают добавиться в PATH при установке, несмотря даже на то, что для пользователя это было бы удобным. Отчасти это может быть связано с тем, что, если все начнут туда добавляться, то переменная PATH неминуемо начнёт расти неконтролируемыми темпами, и очень быстро превысит безопасные лимиты.

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

Конечно, хочется это как-то автоматизировать, чтобы не заморачиваться с этим после установки каждой небольшой программы. К счастью, существует проект Chocolatey, в рамках которого, помимо простых консольных установщиков для множества программ, прилагаются также скрипты для вызова т.н. shimgen — программы для генерации исполняемых файлов в каком-то внутреннем каталоге Chocolatey, который уже добавлен в PATH. Короче говоря, если нужная вам программа доступна через Chocolatey — высока вероятность того, что эта программа или будет корректно добавляться в PATH при установке, или же использует shimgen для размещения ссылок на свои исполняемые файлы в каталоге, который уже добавлен в PATH.

Пользуйтесь Chocolatey, товарищи.

Локальное управление окружением

К сожалению, даже использование Chocolatey не решает всех проблем с присутствием программ в PATH, так что какие-то меры всё-таки приходится предпринимать.

Самое простое, что можно сделать — это добавить псевдонимы для часто используемых программ в профиль используемого вами интерпретатора команд оболочки. Мой профиль PowerShell (а я пользуюсь именно этим интерпретатором) начинается с определений псевдонимов:

New-Alias appcsxcad E:\Programs\openEMS\AppCSXCAD.exe
New-Alias cmake 'c:\Program Files (x86)\CMake\bin\cmake.exe'
New-Alias ccl c:\Programs\ccl-1.9\ccl\wx86cl64.exe
New-Alias dub e:\Programs\dub\dub.exe

Это позволяет вызывать перечисленные команды из PowerShell, не модифицируя переменных окружения и не расходуя ценное место в PATH.

Конечно же, этого зачастую также недостаточно: иногда хочется получить доступ сразу к целому каталогу с исполняемыми файлами, да и в окружении его иметь тоже иногда хочется (например, если мы хотим, чтобы изменённый PATH был доступен дочерним процессам, которые мы запускаем из оболочки — ведь к псевдонимам из локальной сессии PowerShell они не смогут получить доступ). Для этой цели я создаю в профиле специальные функции наподобие вот таких:

function android-environment {
    Add-Path -CurrentUser e:\Programs\AndroidSdk\tools
}

function cabal-environment {
    Add-Path -CurrentUser T:\cabal\bin
}

function git-tfs-environment {
    Add-Path -CurrentUser e:\Programs\GitTfs\
}

function elixir-environment {
    erlang-environment
    Add-Path -CurrentUser c:\ProgramData\chocolatey\Elixir\bin
}

function erlang-environment {
    Add-Path -CurrentUser 'c:\Program Files\erl6.3\bin'
    Add-Path -CurrentUser 'E:\Programs\rebar'
}

В дальнейшем, если я, например, хочу поработать с Elixir, я выполняю команду elixir-environment — и в текущей сессии становятся доступны все исполняемые файлы Elixir. При этом они не засоряют глобального окружения и не появляются в нём до тех пор, пока они мне не окажутся нужны.

Add-Path — это простой скрипт из моего пакета для PowerShell, однако можно достигнуть той же цели прямым модифицированием переменной $env:PATH. Само собой, решение по форме не специфично для PowerShell, и его можно использовать из любого интерпретатора команд, который позволяет модифицировать переменные окружения: например, bash или cmd.

Заключение

Пользуясь этим простым набором подходов, вы никогда больше не окажетесь в ситуации, когда PATH доставляет вам существенные неудобства при работе в Windows. До новых встреч!