HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-21
1 <p><a>#статьи</a></p>
1 <p><a>#статьи</a></p>
2 <ul><li>3 окт 2023</li>
2 <ul><li>3 окт 2023</li>
3 <li>0</li>
3 <li>0</li>
4 </ul><h2>Как появились и менялись переменные окружения</h2>
4 </ul><h2>Как появились и менялись переменные окружения</h2>
5 <p>Детективное расследование о Unix.</p>
5 <p>Детективное расследование о Unix.</p>
6 <p>Иллюстрация: Bell-Labs / Wikimedia commons / Colowgee для Skillbox Media</p>
6 <p>Иллюстрация: Bell-Labs / Wikimedia commons / Colowgee для Skillbox Media</p>
7 <p>Недавно мне нужно было сделать материал для онлайн-урока на тему переменных окружения в Linux. Да, вот про те самые PATH, PS1 и TERM, знакомые каждому, кто хотя бы иногда работает в консоли.</p>
7 <p>Недавно мне нужно было сделать материал для онлайн-урока на тему переменных окружения в Linux. Да, вот про те самые PATH, PS1 и TERM, знакомые каждому, кто хотя бы иногда работает в консоли.</p>
8 <p>Иногда студенты спрашивают у меня: "Это вообще кому-то нужно сегодня?" Ещё как нужно! Окружения - это базовый механизм настройки приложений в любой Unix-подобной системе, будь это ноутбук с macOS, сервер в облаке или контейнер Kubernetes.</p>
8 <p>Иногда студенты спрашивают у меня: "Это вообще кому-то нужно сегодня?" Ещё как нужно! Окружения - это базовый механизм настройки приложений в любой Unix-подобной системе, будь это ноутбук с macOS, сервер в облаке или контейнер Kubernetes.</p>
9 <p>В прекрасном манифесте<a>The twelve-factor app</a>про построение масштабируемых веб-приложений, включая микросервисы, в разделе про конфиги чётко и понятно подаётся мысль: отделяйте конфиги от кода и храните настройки в переменных окружения.</p>
9 <p>В прекрасном манифесте<a>The twelve-factor app</a>про построение масштабируемых веб-приложений, включая микросервисы, в разделе про конфиги чётко и понятно подаётся мысль: отделяйте конфиги от кода и храните настройки в переменных окружения.</p>
10 <p>Техлид в финтех-компании Tabby и автор курсов про тестирование на Python в Skillbox.</p>
10 <p>Техлид в финтех-компании Tabby и автор курсов про тестирование на Python в Skillbox.</p>
11 <p>В далёком 2000 году впервые увидел чёрный экран FreeBSD 4.0 и полюбил Unix-консоль с первого взгляда.</p>
11 <p>В далёком 2000 году впервые увидел чёрный экран FreeBSD 4.0 и полюбил Unix-консоль с первого взгляда.</p>
12 <p>Переменные окружения - это набор значений, которые определяют настройки и поведение операционной системы и программ, работающих в ней. Они представляют собой пары "ключ - значение" и хранятся в памяти, упрощая работу с приложениями. В большинстве статей на этих определениях и заканчивают, не раскрывая деталей реализации.</p>
12 <p>Переменные окружения - это набор значений, которые определяют настройки и поведение операционной системы и программ, работающих в ней. Они представляют собой пары "ключ - значение" и хранятся в памяти, упрощая работу с приложениями. В большинстве статей на этих определениях и заканчивают, не раскрывая деталей реализации.</p>
13 <p>Но важно помнить, что наше понимание работы любой технологии - это модель в нашем сознании, которую можно и нужно уточнять. Сделать это проще всего ретроспективно - посмотреть на ранний этап развития технологии, когда её идея только зародилась и не успела обрасти улучшениями. Давайте посмотрим на то, когда возникли переменные окружения и как они эволюционировали до нашего времени.</p>
13 <p>Но важно помнить, что наше понимание работы любой технологии - это модель в нашем сознании, которую можно и нужно уточнять. Сделать это проще всего ретроспективно - посмотреть на ранний этап развития технологии, когда её идея только зародилась и не успела обрасти улучшениями. Давайте посмотрим на то, когда возникли переменные окружения и как они эволюционировали до нашего времени.</p>
14 <p>Переменные окружения в их современном виде<a>появились в 1979 году</a>в седьмой версии Unix (Unix V7). Если посмотреть на <a>генеалогию Unix-like операционных систем</a>, то мы видим, что эта ОС находится у самых корней дерева, то есть в самом начале эпохи развития Linux, macOS и FreeBSD. Одним из компьютеров, работавших на ней, был PDP-11.</p>
14 <p>Переменные окружения в их современном виде<a>появились в 1979 году</a>в седьмой версии Unix (Unix V7). Если посмотреть на <a>генеалогию Unix-like операционных систем</a>, то мы видим, что эта ОС находится у самых корней дерева, то есть в самом начале эпохи развития Linux, macOS и FreeBSD. Одним из компьютеров, работавших на ней, был PDP-11.</p>
15 Авторы Unix V7 - Деннис Ритчи и Кен Томпсон - перед PDP-11<em>Фото:<a>Bell Labs</a></em><p>Это же больше сорока лет назад! Какую проблему решали авторы, придумывая переменные окружения и само окружение. Актуальны ли они сейчас? Как это работало? Если вы дочитали до этого места и вам тоже интересны ответы на эти вопросы, то давайте начнём вместе искать на них ответы!</p>
15 Авторы Unix V7 - Деннис Ритчи и Кен Томпсон - перед PDP-11<em>Фото:<a>Bell Labs</a></em><p>Это же больше сорока лет назад! Какую проблему решали авторы, придумывая переменные окружения и само окружение. Актуальны ли они сейчас? Как это работало? Если вы дочитали до этого места и вам тоже интересны ответы на эти вопросы, то давайте начнём вместе искать на них ответы!</p>
16 <p>Для начала разберёмся с идеей конфигурации и попробуем ответить на вопрос - почему она появилась? В этом нам поможет Джон, вымышленный сотрудник лаборатории компании<a>DEC</a>. Хай, Джон!</p>
16 <p>Для начала разберёмся с идеей конфигурации и попробуем ответить на вопрос - почему она появилась? В этом нам поможет Джон, вымышленный сотрудник лаборатории компании<a>DEC</a>. Хай, Джон!</p>
17 <p>DEC - это компания, которая разрабатывала компьютеры PDP-11 и другие устройства. В распоряжении нашего Джона был терминал<a>Teletype Model 33</a>, вот как на фото выше. Работать было просто и удобно - Джон запускал исполняемый файл утилиты cat, набирая её имя на терминале. PDP-11 печатал результат запуска приложения со скоростью 100 слов в минуту, строка за строкой, как печатная машинка. Шумновато, но быстро.</p>
17 <p>DEC - это компания, которая разрабатывала компьютеры PDP-11 и другие устройства. В распоряжении нашего Джона был терминал<a>Teletype Model 33</a>, вот как на фото выше. Работать было просто и удобно - Джон запускал исполняемый файл утилиты cat, набирая её имя на терминале. PDP-11 печатал результат запуска приложения со скоростью 100 слов в минуту, строка за строкой, как печатная машинка. Шумновато, но быстро.</p>
18 <p>Всё отлично работало, но прогресс не стоял на месте. Спустя небольшое время DEC разработала видеотерминал<a>VT52</a>и один из них попал к Джону.</p>
18 <p>Всё отлично работало, но прогресс не стоял на месте. Спустя небольшое время DEC разработала видеотерминал<a>VT52</a>и один из них попал к Джону.</p>
19 Видеотерминал VT52<em>Фото:<a>Columbia University</a></em><p>Новый терминал отличается от старого - вместо листа бумаги у него дисплей! Из-за этого поменялось число выводимых символов: в Teletype Model 33 помещалось 72 символа в строке, а в VT52 уже 80 символов. Поменять эти значения невозможно: Teletype Model 33 - это печатная машинка, да и VT52 умеет отображать только символы<a>ASCII</a>и только одного размера.</p>
19 Видеотерминал VT52<em>Фото:<a>Columbia University</a></em><p>Новый терминал отличается от старого - вместо листа бумаги у него дисплей! Из-за этого поменялось число выводимых символов: в Teletype Model 33 помещалось 72 символа в строке, а в VT52 уже 80 символов. Поменять эти значения невозможно: Teletype Model 33 - это печатная машинка, да и VT52 умеет отображать только символы<a>ASCII</a>и только одного размера.</p>
20 <p>Но версия<strong>cat</strong>, которую использовал Джон, в работе рассчитывает на то, что в строке только 72 символа. Надо собирать новые версии приложений с поддержкой VT52. Выходит, будет две версии cat под разные терминалы, различающиеся только одной небольшой настройкой? Это нерационально, тем более количество вариантов устройств может увеличиваться и дальше. Но cat не понимает, за каким терминалом сейчас работает Джон.</p>
20 <p>Но версия<strong>cat</strong>, которую использовал Джон, в работе рассчитывает на то, что в строке только 72 символа. Надо собирать новые версии приложений с поддержкой VT52. Выходит, будет две версии cat под разные терминалы, различающиеся только одной небольшой настройкой? Это нерационально, тем более количество вариантов устройств может увеличиваться и дальше. Но cat не понимает, за каким терминалом сейчас работает Джон.</p>
21 <p>Самый простой способ объяснить ему это - при запуске приложения указывать параметр, соответствующий терминалу. Например, так: cat TERM=dumb для Teletype Model 33 и cat TERM=vt52 для нового терминала с монитором. Джон договаривается с <a>Деннисом Ритчи</a>, и скоро появляется cat с поддержкой любой длины строк. Теперь можно использовать его и на новом, и на старом устройстве, указывая нужный параметр.</p>
21 <p>Самый простой способ объяснить ему это - при запуске приложения указывать параметр, соответствующий терминалу. Например, так: cat TERM=dumb для Teletype Model 33 и cat TERM=vt52 для нового терминала с монитором. Джон договаривается с <a>Деннисом Ритчи</a>, и скоро появляется cat с поддержкой любой длины строк. Теперь можно использовать его и на новом, и на старом устройстве, указывая нужный параметр.</p>
22 <p>Параметризация приложения дала нам возможность использовать один и тот же файл приложения в разных случаях. С этой идеей разобрались, но зачем понадобилось разделить конфигурацию на параметры приложения и на окружение?</p>
22 <p>Параметризация приложения дала нам возможность использовать один и тот же файл приложения в разных случаях. С этой идеей разобрались, но зачем понадобилось разделить конфигурацию на параметры приложения и на окружение?</p>
23 <p>К тому моменту в Unix было написано уже несколько десятков приложений. В каждое из них пришлось добавлять поддержку параметра TERM, который подсказывал, с каким окружением приходится иметь дело. Но указывать TERM в параметрах - лишняя работа. Идеальный вариант - настроить всё окружение один раз и предоставить Unix самостоятельно подставлять параметры этих настроек для всех запускаемых приложений. Этот механизм - разделение параметров на окружение и собственно параметры приложения - и был реализован в Unix V7.</p>
23 <p>К тому моменту в Unix было написано уже несколько десятков приложений. В каждое из них пришлось добавлять поддержку параметра TERM, который подсказывал, с каким окружением приходится иметь дело. Но указывать TERM в параметрах - лишняя работа. Идеальный вариант - настроить всё окружение один раз и предоставить Unix самостоятельно подставлять параметры этих настроек для всех запускаемых приложений. Этот механизм - разделение параметров на окружение и собственно параметры приложения - и был реализован в Unix V7.</p>
24 <p>Помещая часть настроек в окружение, мы можем не настраивать каждое приложение по отдельности.</p>
24 <p>Помещая часть настроек в окружение, мы можем не настраивать каждое приложение по отдельности.</p>
25 <p>Идея понятна, спасибо Джону!</p>
25 <p>Идея понятна, спасибо Джону!</p>
26 <p>Как же выглядела настройка окружения в одной из самых первых версий Unix? Посмотрим в руководство UNIX Time Sharing System -<a>UNIX Programmer’s Manual - Seventh Edition, Volume 1A</a>от января 1979 года. На странице 161 в разделе про командный интерпретатор Shell есть информация и про окружение (environment).</p>
26 <p>Как же выглядела настройка окружения в одной из самых первых версий Unix? Посмотрим в руководство UNIX Time Sharing System -<a>UNIX Programmer’s Manual - Seventh Edition, Volume 1A</a>от января 1979 года. На странице 161 в разделе про командный интерпретатор Shell есть информация и про окружение (environment).</p>
27 <p>Резюмирую для вас то, что там написано:</p>
27 <p>Резюмирую для вас то, что там написано:</p>
28 <ul><li>Окружение - это список пар "ключ - значение", который передаётся выполняемой программе так же, как и обычный список аргументов.</li>
28 <ul><li>Окружение - это список пар "ключ - значение", который передаётся выполняемой программе так же, как и обычный список аргументов.</li>
29 <li>Для добавления переменных окружения используйте новую команду export.</li>
29 <li>Для добавления переменных окружения используйте новую команду export.</li>
30 <li>Запускаемые из Shell команды наследуют одно и то же окружение.</li>
30 <li>Запускаемые из Shell команды наследуют одно и то же окружение.</li>
31 <li>Shell создаёт из переменных окружения параметры.</li>
31 <li>Shell создаёт из переменных окружения параметры.</li>
32 </ul><p>Всё работает точно так же, как и в современной Unix-подобной операционной системе. Более того, в мануале упоминаются переменные окружения PATH, HOME, TERM и другие, привычные нам по современной разработке.</p>
32 </ul><p>Всё работает точно так же, как и в современной Unix-подобной операционной системе. Более того, в мануале упоминаются переменные окружения PATH, HOME, TERM и другие, привычные нам по современной разработке.</p>
33 <p>С точки зрения пользователя способ работы с переменными окружения был придуман ещё на заре Unix и остался неизменным до сих пор.</p>
33 <p>С точки зрения пользователя способ работы с переменными окружения был придуман ещё на заре Unix и остался неизменным до сих пор.</p>
34 <p>В этом месте мне стало понятно, что в материалы онлайн-урока это упражнение, конечно, не войдёт, но своё "расследование" остановить уже не мог. Я решил разобраться - где в Unix хранилось это самое окружение?</p>
34 <p>В этом месте мне стало понятно, что в материалы онлайн-урока это упражнение, конечно, не войдёт, но своё "расследование" остановить уже не мог. Я решил разобраться - где в Unix хранилось это самое окружение?</p>
35 <p>Чтобы понять, что в Unix было сделано для работы окружения, опять загляну в документацию, ссылки из раздела про Shell ведут нас в <a>ENVIRON (5)</a>(пятёрка и другие числа в скобках далее - это номер раздела в документации).</p>
35 <p>Чтобы понять, что в Unix было сделано для работы окружения, опять загляну в документацию, ссылки из раздела про Shell ведут нас в <a>ENVIRON (5)</a>(пятёрка и другие числа в скобках далее - это номер раздела в документации).</p>
36 <p>Документация лаконична. Environ - это глобальная переменная, которая создаётся в результате вызова<a>EXEC (2)</a>. Раз это глобальная переменная, то окружение хранится в памяти процесса. А процесс в операционной системе - это запущенный исполняемый файл в ней.</p>
36 <p>Документация лаконична. Environ - это глобальная переменная, которая создаётся в результате вызова<a>EXEC (2)</a>. Раз это глобальная переменная, то окружение хранится в памяти процесса. А процесс в операционной системе - это запущенный исполняемый файл в ней.</p>
37 <p>Но что такое вызов EXEC и как он создавал в памяти приложения Environ?</p>
37 <p>Но что такое вызов EXEC и как он создавал в памяти приложения Environ?</p>
38 <p>Вызов EXEC происходит во время работы пользователя в Shell. Когда он хочет запустить приложение, то набирает путь к его исполняемому файлу и предоставляет остальную работу Shell. Последний тоже не запускает приложение сам - он вызывает EXEC, передавая в нём параметры запуска приложения и параметры управления запуском операционной системы Unix.</p>
38 <p>Вызов EXEC происходит во время работы пользователя в Shell. Когда он хочет запустить приложение, то набирает путь к его исполняемому файлу и предоставляет остальную работу Shell. Последний тоже не запускает приложение сам - он вызывает EXEC, передавая в нём параметры запуска приложения и параметры управления запуском операционной системы Unix.</p>
39 <p>Как же Unix обрабатывала EXEC? Посмотрим на <a>документацию</a>. Запуская программу на C, операционная система вызывает функцию main с аргументами main (argc, argv, envp). В argc, argv задаётся количество аргументов, которые были переданы, и список указателей на них. А вот envp - это указатель на окружение родительского процесса. В нашем примере это Shell, со всеми его переменными.</p>
39 <p>Как же Unix обрабатывала EXEC? Посмотрим на <a>документацию</a>. Запуская программу на C, операционная система вызывает функцию main с аргументами main (argc, argv, envp). В argc, argv задаётся количество аргументов, которые были переданы, и список указателей на них. А вот envp - это указатель на окружение родительского процесса. В нашем примере это Shell, со всеми его переменными.</p>
40 <p>Но ещё до того, как выполнится main, будет создана копия того окружения, что находится в envp, и приложению она будет доступна как глобальная переменная environ. За заполнение списка переменных отвечает Shell, а за создание копии этого списка в памяти создаваемого процесса - сама операционная система.</p>
40 <p>Но ещё до того, как выполнится main, будет создана копия того окружения, что находится в envp, и приложению она будет доступна как глобальная переменная environ. За заполнение списка переменных отвечает Shell, а за создание копии этого списка в памяти создаваемого процесса - сама операционная система.</p>
41 <p>Получается, что новый процесс получает копию окружения своего родительского процесса. Благодаря такому копированию, каждое приложение может менять свою копию настроек, не заботясь о том, что это сломает другие приложения. А если новый процесс тоже запустит приложение, то создастся дочерний процесс, который получит копию окружения уже родителя, но не его предков.</p>
41 <p>Получается, что новый процесс получает копию окружения своего родительского процесса. Благодаря такому копированию, каждое приложение может менять свою копию настроек, не заботясь о том, что это сломает другие приложения. А если новый процесс тоже запустит приложение, то создастся дочерний процесс, который получит копию окружения уже родителя, но не его предков.</p>
42 <p>Работа с переменными окружения была поддержана в вызовах Unix, а каждое приложение имело собственную копию окружения родительского процесса в своей памяти.</p>
42 <p>Работа с переменными окружения была поддержана в вызовах Unix, а каждое приложение имело собственную копию окружения родительского процесса в своей памяти.</p>
43 <p>Первое появление понятия окружения в седьмой версии Unix подтверждает то, что в <a>мануалах шестой версии</a>упоминаний про это нет. В документации про вызов EXEC (2) есть только два параметра - argc и argv, а envp отсутствует, то есть окружений ещё не было.</p>
43 <p>Первое появление понятия окружения в седьмой версии Unix подтверждает то, что в <a>мануалах шестой версии</a>упоминаний про это нет. В документации про вызов EXEC (2) есть только два параметра - argc и argv, а envp отсутствует, то есть окружений ещё не было.</p>
44 <p>Ещё в дополнении к мануалу V7 -<a>Annotated Excerpts from the Programmer’s Manual</a> - можно найти замечание о том, что привычная нам Shell (Bourne shell) была написана как раз для седьмой версии, заменив предыдущую. Без поддержки в Shell окружение не было бы таким удобным для работы.</p>
44 <p>Ещё в дополнении к мануалу V7 -<a>Annotated Excerpts from the Programmer’s Manual</a> - можно найти замечание о том, что привычная нам Shell (Bourne shell) была написана как раз для седьмой версии, заменив предыдущую. Без поддержки в Shell окружение не было бы таким удобным для работы.</p>
45 <p>Итак, у нас есть ответы на все вопросы, но я хочу посмотреть, что стало с окружением в современном Linux. Может быть, управление им изменилось?</p>
45 <p>Итак, у нас есть ответы на все вопросы, но я хочу посмотреть, что стало с окружением в современном Linux. Может быть, управление им изменилось?</p>
46 <p>Проверку делаю на Linux, запущенном в Docker, а для решения задачи использую джентльменский набор разработчика: утилиту Strace для просмотра системных вызовов и утилиту GDB для просмотра содержимого памяти у процессов.</p>
46 <p>Проверку делаю на Linux, запущенном в Docker, а для решения задачи использую джентльменский набор разработчика: утилиту Strace для просмотра системных вызовов и утилиту GDB для просмотра содержимого памяти у процессов.</p>
47 <p>Перед тем как смотреть на вызовы, сначала представлю себе, что я хочу увидеть. Отправной точкой будет вызов exec(). Почему он? Начиная с 1988 года существуют стандарты<a>POSIX</a>, определяющие то, как должны выглядеть системные вызовы.</p>
47 <p>Перед тем как смотреть на вызовы, сначала представлю себе, что я хочу увидеть. Отправной точкой будет вызов exec(). Почему он? Начиная с 1988 года существуют стандарты<a>POSIX</a>, определяющие то, как должны выглядеть системные вызовы.</p>
48 <p>Unix V7, про который мы говорили, появился раньше, но стандарты POSIX разрабатывались в основном под влиянием Unix-подобных систем. Поэтому Linux можно считать в большой степени POSIX-совместимым, а значит, мы можем искать в нём похожий вызов.</p>
48 <p>Unix V7, про который мы говорили, появился раньше, но стандарты POSIX разрабатывались в основном под влиянием Unix-подобных систем. Поэтому Linux можно считать в большой степени POSIX-совместимым, а значит, мы можем искать в нём похожий вызов.</p>
49 <p>В этот раз мне не нужно читать документацию в интернете. К моим услугам команда man, которая показывает документацию по использованию других команд.</p>
49 <p>В этот раз мне не нужно читать документацию в интернете. К моим услугам команда man, которая показывает документацию по использованию других команд.</p>
50 <p>Запускаем в контейнере Ubuntu команду man exec и вновь открываем мануал. В Linux exec это целое семейство вызовов, но тут есть и глобальная переменная environ, и передача окружения через указатель envp. Но, чтобы нам подсмотреть в strace нужный вызов, нам надо знать его имя, судя по тому же man exec, это должен быть вызов execve. Благодаря POSIX-стандартам механизмы работы окружения в Linux очень похожи на те же механизмы в Unix V7<em>.</em></p>
50 <p>Запускаем в контейнере Ubuntu команду man exec и вновь открываем мануал. В Linux exec это целое семейство вызовов, но тут есть и глобальная переменная environ, и передача окружения через указатель envp. Но, чтобы нам подсмотреть в strace нужный вызов, нам надо знать его имя, судя по тому же man exec, это должен быть вызов execve. Благодаря POSIX-стандартам механизмы работы окружения в Linux очень похожи на те же механизмы в Unix V7<em>.</em></p>
51 <p>Теперь запустим команду cat из Bash shell, чтобы увидеть параметры вызова:</p>
51 <p>Теперь запустим команду cat из Bash shell, чтобы увидеть параметры вызова:</p>
52 strace -f -p &lt;pid of bash&gt; -e trace=execve strace: Process 3238 attached strace: Process 10145 attached [pid 10145] execve("/usr/bin/cat", ["cat"], 0xaaaadacacb50 /* 12 vars */) = 0<p>Да, третьим аргументом передаётся список переменных, на него ссылается указатель 0xaaaadacacb50. Что там внутри у этого списка? Надо перезапустить strace с ключом -v:</p>
52 strace -f -p &lt;pid of bash&gt; -e trace=execve strace: Process 3238 attached strace: Process 10145 attached [pid 10145] execve("/usr/bin/cat", ["cat"], 0xaaaadacacb50 /* 12 vars */) = 0<p>Да, третьим аргументом передаётся список переменных, на него ссылается указатель 0xaaaadacacb50. Что там внутри у этого списка? Надо перезапустить strace с ключом -v:</p>
53 strace -v -f -p &lt;pid of bash&gt; -e trace=execve [pid 10149] execve("/usr/bin/cat", ["cat"], ["PID=3238","HOSTNAME=7057e22ae57d", "PWD=/root", "HOME=/root", "LS_COLORS=rs=0:di=01;34:ln=01;36"..., "TERM=xterm", "SHLVL=2", "PATH=/usr/local/sbin:/usr/local/"..., "OLDPWD=/", "_=/usr/bin/cat"]) = 0<p>Вот и наши знакомые переменные окружения в третьем параметре: PID, HOSTNAME, HOME и другие. Получается, что тут мало что отличается от вызова exec() времён Unix седьмой версии. Ну разве что не надо считать аргументы.</p>
53 strace -v -f -p &lt;pid of bash&gt; -e trace=execve [pid 10149] execve("/usr/bin/cat", ["cat"], ["PID=3238","HOSTNAME=7057e22ae57d", "PWD=/root", "HOME=/root", "LS_COLORS=rs=0:di=01;34:ln=01;36"..., "TERM=xterm", "SHLVL=2", "PATH=/usr/local/sbin:/usr/local/"..., "OLDPWD=/", "_=/usr/bin/cat"]) = 0<p>Вот и наши знакомые переменные окружения в третьем параметре: PID, HOSTNAME, HOME и другие. Получается, что тут мало что отличается от вызова exec() времён Unix седьмой версии. Ну разве что не надо считать аргументы.</p>
54 <p>Продолжим расследование. В описании вызовов нет подсказок, где найти переменные окружения в памяти запущенного процесса. Но посмотреть интересно, ведь вот оно, то самое окружение, о котором мы так много говорим.</p>
54 <p>Продолжим расследование. В описании вызовов нет подсказок, где найти переменные окружения в памяти запущенного процесса. Но посмотреть интересно, ведь вот оно, то самое окружение, о котором мы так много говорим.</p>
55 <p>У меня есть подсказка - адрес указателя из strace - 0xaaaadacacb50. Посмотрим, что хранится по этому указателю в памяти bash:</p>
55 <p>У меня есть подсказка - адрес указателя из strace - 0xaaaadacacb50. Посмотрим, что хранится по этому указателю в памяти bash:</p>
56 gdb /bin/bash &lt;pid of bash&gt; (gdb)x/s *(char **)0xaaaadacacb50 0xaaaadacf3870: "PID=3238"<p>Ого, да это как раз и есть указатель на начало окружения процесса bash. Мы можем попутешествовать по адресам этих указателей и увидеть, что они содержат наши переменные окружения:</p>
56 gdb /bin/bash &lt;pid of bash&gt; (gdb)x/s *(char **)0xaaaadacacb50 0xaaaadacf3870: "PID=3238"<p>Ого, да это как раз и есть указатель на начало окружения процесса bash. Мы можем попутешествовать по адресам этих указателей и увидеть, что они содержат наши переменные окружения:</p>
57 (gdb) x/s *(char **)(0xaaaadacacb50+32) 0xaaaadaccbca0: "HOME=/root<p>Теперь, кажется, пришла пора остановиться.</p>
57 (gdb) x/s *(char **)(0xaaaadacacb50+32) 0xaaaadaccbca0: "HOME=/root<p>Теперь, кажется, пришла пора остановиться.</p>
58 <p>Я давно работаю в консоли, поэтому переменные окружения - привычный и тривиальный инструмент. Для меня было открытием, как давно им пользуются в неизменном виде.</p>
58 <p>Я давно работаю в консоли, поэтому переменные окружения - привычный и тривиальный инструмент. Для меня было открытием, как давно им пользуются в неизменном виде.</p>
59 <p>Первые версии Unix уже давно не используют, но именно они заложили фундамент операционных систем, который можно найти на своём компьютере с macOS или Linux. Потребуется только любопытство, старые версии мануалов и понимание того, куда смотреть.</p>
59 <p>Первые версии Unix уже давно не используют, но именно они заложили фундамент операционных систем, который можно найти на своём компьютере с macOS или Linux. Потребуется только любопытство, старые версии мануалов и понимание того, куда смотреть.</p>
60 <p>Хочу сказать спасибо стараниям тех, кто сохраняет и выкладывает в общий доступ документацию старых версий приложений. Без них у меня бы не получилось это маленькое исследование.</p>
60 <p>Хочу сказать спасибо стараниям тех, кто сохраняет и выкладывает в общий доступ документацию старых версий приложений. Без них у меня бы не получилось это маленькое исследование.</p>
61 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>
61 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>