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 <pid of bash> -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 <pid of bash> -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 <pid of bash> -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 <pid of bash> -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 <pid of bash> (gdb)x/s *(char **)0xaaaadacacb50 0xaaaadacf3870: "PID=3238"<p>Ого, да это как раз и есть указатель на начало окружения процесса bash. Мы можем попутешествовать по адресам этих указателей и увидеть, что они содержат наши переменные окружения:</p>
56
gdb /bin/bash <pid of bash> (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>