Понимание области действия и времени жизни переменных среды в сценариях оболочки

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

Я пытаюсь выполнить скрипт 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 снова, и окружающая среда не проходит мимо. Похоже, вы нашли единственные способы реализовать функциональность, которую вы хотите, используя среду - каждый раз форсировать создание нового процесса. Другие подходы включают передачу необходимых данных другими средствами, такими как командная строка или файл.

Другие вопросы по тегам