Розуміння сфери та терміну експлуатації змінних середовища в сценарії оболонок


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(), він щоразу запускає новий сеанс терміналу з правильними змінними середовища. Але це щоразу відкриває абсолютно новий екземпляр Терміналу.

оновлення:

Я трохи спростив процес, використовуючи лише один сценарій замість двох зараз, перевіривши змінну середовища 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

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

Що стосується вашого іншого питання: змінні середовища передаються від батьківського процесу до дочірнього процесу (тобто при створенні нового процесу через fork) і зберігаються через execвиклики. Таким чином вони йдуть вниз по ієрархії процесів, поки процес не вийде або явно не змінить змінну. Отже, схоже, що перший openвикликає термінал a forkі execTerminal, тим самим передаючи оточення, тоді як другий openпросто надсилає повідомлення існуючому процесу, щоб запуститися ../Unix Support/test.phpзнову, і оточення не проходить. Здається, ви знайшли єдиний спосіб реалізувати функціонал, який ви хочете використовувати за допомогою середовища - щоразу примушуйте створювати новий процес. Інші підходи передбачають передачу необхідних даних іншими способами, наприклад командним рядком або файлом.


Скотт, спасибі. Ваша остання пропозиція - це те, що я тим часом зробив і тим часом. Я спростив речі, використовуючи лише один сценарій зараз, випробувавши змінну середовища, яку називають SHLVLпереданою, щоб побачити, чи є сценарій батьків чи дочір, і дійсно зберегти середовище у тимчасовому файлі, якщо він є батьківським, і читати та putenv()-ing їх , якщо це дочірній сценарій. Але це не дуже елегантно. Ви впевнені, що крім кліпу чи файлу немає більш елегантного способу оновлення змінних оточення для одного і того ж сеансу терміналу?
Гідний даблер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.