1

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

Я пытаюсь выполнить скрипт 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() , он каждый раз запускает новый сеанс Terminal с правильные переменные среды. Но это каждый раз открывает совершенно новый экземпляр Terminal.

Обновить:

Я немного упростил процесс, используя только один сценарий вместо двух, тестируя переменную окружения SHLVL . Мне также удалось покончить с новым экземпляром Terminal, используя временный файл, как предложил Скотт. Это привело к следующему. Но я все еще чувствую, что это не очень элегантно.

$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 ответ1

1

Вы когда-нибудь использовали Microsoft Office (Word, Excel и PowerPoint)?  Вы когда-нибудь открывали два документа / рабочих тетради / презентации одновременно?  Вы заметили, что вы обычно получаете только один процесс соответствующего инструмента, даже если у вас есть два окна?  Совершенно очевидно, что это или что-то похожее происходит с Терминалом - второй запрос на open обрабатывается процессом, который был создан при первом open , и обрабатывается без создания нового процесса.  Я предполагаю, что open обнаруживает, что процесс уже существует, и просто отправляет ему сообщение, а не создает новый процесс или что-то в этом роде.

Что касается вашего другого вопроса: переменные среды передаются из родительского процесса в дочерний процесс (т. Е. При создании нового процесса с помощью fork) и сохраняются в вызовах exec .  Таким образом, они идут вниз по иерархии процессов, пока процесс не выйдет или не изменит явно переменную.  Таким образом, похоже, что первое open вызывает fork и exec терминала, тем самым пропуская среду, тогда как второе open просто отправляет сообщение существующему процессу для запуска ../Unix Support/test.php раз, и среда не проходит.  Похоже, вы нашли единственные способы реализовать функциональность, которую вы хотите, используя среду - каждый раз форсировать создание нового процесса.  Другие подходы включают передачу необходимых данных другими способами, такими как командная строка или файл.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .