Змінні оточення
Раніше ми познайомилися з тим, як отримувати параметри в програмі за допомогою сімейства функцій getopt (детальніше читайте "Крок 10 - Передача опцій в програму - getopt" та "Крок 11 - Передача довгих опцій в програму - getopt_long"). Але існує ще один метод - змінні оточення або змінні середовища. З ними ми встигли вже познайомитися раніше в кроці "Крок 13 - Отримання інформації про користувача". За допомогою даних змінних можна передавати в програму додаткові специфічні параметри, які можуть використовуватися кількома програмами одночасно і вони характеризують "середовище", в якій виконується програма.
Наприклад, якщо Ви розробляєте якусь систему що складається з декількох програм працюють незалежно, то наприклад, Ви захочете повідомити всім програмам робочий каталог, тимчасову директорію або який-небудь інший специфічний параметр. Тоді змінні оточення, це єдиний розумний метод, адже передавати такі параметри через командний рядок нерозумно. Чому?! Ну, наприклад, наведу скрипт запуску якої-небудь складної системи:
- ! / Bin / bash
/ Yoyosystem / cheduler - time = 60 - work-dir = / yoyosystem / data - temp-dir = / tmp / yoyosystem / Yoyosystem / counter-c 25-w 31 - work-dir = / yoyosystem / data - temp-dir = / tmp / yoyosystem / Yoyosystem / pusher - stack-size = 512-m 12 - work-dir = / yoyosystem / data - temp-dir = / tmp / yoyosystem
Ну, як?! Громодко! А ось як більш красиво:
- ! / Bin / bash
export YOYO_WORK_DIR = "/ yoyosystem / data" export YOYO_TEMP_DIR = "/ tmp / yoyosystem"
/ Yoyosystem / cheduler - time = 60 / Yoyosystem / counter-c 25-w 31 / Yoyosystem / pusher - stack-size = 512-m 12
Кожна із зазначених програм буде брати параметри про використовувані директоріях з змінних середовища YOYO_WORK_DIR і YOYO_TEMP_DIR, що значно спрощує написання і модифікацію скрипта запуску системи, а також убереже від помилок і пов'язаних з цим помилок. Тому змінні середовища досить важливі і Ви завжди повинні пам'ятати про їх зручність.
А тепер власне давайте познайомимося з цими змінними середовища. Бібліотека glibc надає весь спектр функцій для роботи з ними в заголовному файлі stdlib.h.
Спочатку познайомимося з самим масивом змінних оточення, що визначений в заголовному файлі unistd.h в такому вигляді: / * NULL-terminated array of "NAME = VALUE" environment variables. * / extern char ** __environ;
- Ifdef __USE_GNU
extern char ** environ;
- Endif
Представлет собою масив покажчиків на рядка формату "ім'я = значення" та закінчується нульовим покажчиком NULL. Давайте спробуємо написати програму виведення всіх змінних:
- Include <stdlib.h>
- Include <unistd.h>
int main (int argc, char ** argv) {
int i = 0;
while (__environ [i]! = NULL) { printf ("% s \ n", __environ [i]); i + +; }; return 0;
};
Дана програма виведе весь список змінних середовища оточення, які доступні програмі: root @ darkstar :/@@@@@@#. / a.out MANPATH = / usr / local / man: / usr / man: / usr/X11R6/man: / usr / lib / java / man HOSTNAME = darkstar.example.net SHELL = / bin / bash TERM = xterm USER = root MC_TMPDIR = / tmp / mc-root T1LIB_CONFIG = / usr/share/t1lib/t1lib.config MINICOM =- c on PATH = / usr / local / sbin: / usr / sbin: / sbin: / usr / local / bin: / usr / bin: / bin: / usr/X11R6/bin: MAIL = / var / mail / root LC_COLLATE = C PWD =/@@@@@ INPUTRC = / etc / inputrc JAVA_HOME = / usr / lib / java LANG = en_US PS1 = \ u @ \ h: \ w \ $ HISTCONTROL = ignorespace PS2 => HOME = / root SHLVL = 2 LOGNAME = root LESS =- M LESSOPEN = | lesspipe.sh% s OLDPWD = / usr / include _ =. / A.out
Я звичайно вирізав деякі змінні, які занадто великі, але все одно достатньо інформативно і можна вважати, що програма знає про середовище в якій запущена практично все.
Для доступу до змінних оточення, є кілька функцій: char * getenv (const char * name) - повертає покажчик на значення змінної з ім'ям name, якщо змінна середовища не знайдена, то повертається NULL. Не рекомендується модифіковані значення отриманого рядка, так як вона вказує безпосередньо в масив змінних середовища, і можна зіпсувати їх значення. У зв'язку з цим також не потрібно виділення додаткової пам'яті для збереження результату. int setenv (const char * name, const char * value, int replace) - додає нове або замінює старе значення в масиві змінних середовища з ім'ям name і значенням value (навіть якщо value порожній рядок). Під нову змінну виділяється пам'ять і заноситься рядок виду "ім'я = значення". Якщо в змінних середовища вже є змінна з ім'ям name, то процес заміни контролюється параметром replace, якщо він дорівнює нулю, то ніяких дій не проводиться. int putenv (char * string) - додає або видаляє змінну оточення. Щоб додати або змінити змінної використовуйте рядок формату "ім'я = значення", для видалення просто "ім'я". На відміну від setenv () функція putenv () не виділяє пам'ять для параметра, а використовує покажчик на значення string, тому після виклику цієї функції будь-яка зміна рядка string автоматично призведе до зміни змінної середовища. Також перед видаленням рядка з пам'яті, слід спочатку видалити цю змінну з масиву змінних оточення. int unsetenv (const char * name) - видаляє повністю з масиву змінних оточення змінну з ім'ям name. int clearenv (void) - повністю очищає масив змінних оточення.
Використовуючи набір даних функцій ви можете повністю управляти змінними середовища, які доступні вашій програмі.
- Include <stdlib.h>
int main (int argc, char ** argv) {
char * HOME = getenv ("HOME"); char * USER = getenv ("USER");
printf ("Home directory: \"% s \ "\ n", HOME); printf ("User name: \"% s \ "\ n", USER);
return 0;
};
При виклику даної програми ви дізнаєтеся свій домашній каталог та ім'я користувача. Наприклад: root @ darkstar :/@@@@@@#. / a.out Home directory: "/ root" User name: "root"
Використання змінних оточення корисно не тільки, коли Вам потрібно налаштувати в декількох програмах якісь параметри, але і для обміну даними між процесами. Тобто в одній програмі Ви створюєте змінну, а в іншій отримуєте значення цієї змінної. Таким чином можна налагодити обмін простими короткими даними між процесами. Але, звичайно, все-таки не варто сильно зловживати цією можливістю