Понимание области действия и времени жизни переменных среды в сценариях оболочки
Я пытаюсь понять скрипты оболочки и передать переменные окружения, а что нет.
Я пытаюсь выполнить скрипт PHP из TextWrangler, который в свою очередь открывает новый скрипт PHP с терминалом. (TextWrangler - это текстовый редактор, который имеет возможность выполнять сценарии, расположенные в указанной папке, например, для работы с текущим активным документом).
Первый скрипт находится в:
/Users/<username>/Library/Application Support/TextWrangler/Scripts/
... и его содержание:
#!/usr/bin/php
<?php
var_dump( $_SERVER );
chdir( __DIR__ );
$file = realpath( '../Unix Support/test.php' );
exec( sprintf( 'open -a Terminal "%s" &', $file ) );
exit( 0 );
?>
Второй в:
/Users/<username>/Library/Application Support/TextWrangler/Unix Support/
... и его содержание:
#!/usr/bin/php
<?php
var_dump( $_SERVER );
exit( 0 );
?>
TextWrangler передает некоторые переменные окружения в первый скрипт (доступ к которому я могу получить через $_SERVER
), и они, как и ожидалось. Например, правильный путь к файлу текущего документа, который активен в TextWrangler.
При первом запуске сценария переменные среды автоматически передаются во второй сценарий (который я открываю с exec()
) также.
Теперь наступает расстраивающая часть: когда я переключаю активный документ в TextWrangler и снова запускаю сценарий, первый сценарий снова получает правильные переменные среды из TextWrangler, но второй сценарий все еще имеет старые переменные среды, если только я заранее не уничтожил Terminal. Очевидно, что сеанс терминала как-то запоминает первые переменные окружения и не хочет обновляться.
Но кроме этого очень простого понимания, я не имею ни малейшего представления о том, как работают переменные среды, какова их область действия и т. Д. Итак, кто-то может объяснить, как я могу сделать это так (если возможно, для начала), что второй скрипт снова получает правильные переменные окружения, без необходимости каждый раз завершать работу терминала?
Я пытался явно установить переменные окружения в первом скрипте перед вызовом exec()
, вот так:
foreach( $_SERVER as $key => $value )
{
putenv( "$key=$value" );
}
exec( ... etc. );
Я попытался сбросить переменные окружения в конце, как в первом, так и во втором скриптах, вот так:
foreach( $_SERVER as $key => $value )
{
putenv( "$key" );
}
Но ничего не работает, как я ожидаю. Любые новые идеи тщательно оценены.
редактировать:
Тем временем я нашел альтернативное, но неудовлетворительное решение: когда я звоню open -n -a Terminal ...
(обратите внимание на добавленный -n
аргумент) с exec()
, он начинает новый сеанс терминала каждый раз с правильными переменными среды. Но это каждый раз открывает совершенно новый экземпляр терминала.
Обновить:
Я немного упростил процесс, используя только один сценарий вместо двух, тестируя переменную окружения. SHLVL
, Мне также удалось покончить с новым экземпляром терминала, используя временный файл, как предложил Скотт. Это привело к следующему. Но я все еще чувствую, что это не очень элегантно.
$shellLevel = getenv( 'SHLVL' );
if( 1 == $shellLevel )
{
file_put_contents( 'env.dat', serialize( $_SERVER ) );
exec( sprintf( 'open -a Terminal "%s" &', __FILE__ ) );
exit( 0 );
}
else
{
$_SERVER = unserialize( file_get_contents( 'env.dat' ) );
unlink( 'env.dat' );
foreach( $_SERVER as $key => $value )
{
putenv( "$key=$value" );
}
}
Так что я все еще открыты для других предложений (кроме CLI и файловых предложений, которые Скотт уже предложил). Если, конечно, это просто невозможно (Скотт, казалось, уже намекал на это).
1 ответ
Вы когда-нибудь использовали Microsoft Office (Word, Excel и PowerPoint)? Вы когда-нибудь открывали два документа / рабочих тетради / презентации одновременно? Вы заметили, что вы обычно получаете только один процесс соответствующего инструмента, даже если у вас есть два окна? Совершенно ясно, что это или что-то похожее происходит с Терминалом - второй open
запрос обрабатывается процессом, который был создан первым open
и это обрабатывается без создания нового процесса. Похоже open
обнаруживает, что процесс уже существует, и просто отправляет ему сообщение, а не создает новый процесс или что-то в этом роде.
Что касается вашего другого вопроса: переменные среды передаются из родительского процесса в дочерний процесс (т. Е. При создании нового процесса через fork
) и сохранились по всей exec
звонки. Таким образом, они идут вниз по иерархии процессов, пока процесс не выйдет или явно не изменит переменную. Итак, похоже, что первый open
вызывает fork
и exec
терминала, таким образом, передавая окружающую среду, тогда как второй open
просто отправляет сообщение существующему процессу для запуска ../Unix Support/test.php
снова, и окружающая среда не проходит мимо. Похоже, вы нашли единственные способы реализовать функциональность, которую вы хотите, используя среду - каждый раз форсировать создание нового процесса. Другие подходы включают передачу необходимых данных другими средствами, такими как командная строка или файл.