Entendendo o escopo e o tempo de vida das variáveis de ambiente no shell script

1

Estou puxando o meu cabelo tentando entender o script de shell e passando variáveis de ambiente, e quais não.

Estou tentando executar um script PHP do TextWrangler, que, por sua vez, abre um novo script PHP com o Terminal. (TextWrangler é um editor de texto que tem a opção de executar scripts, localizados em uma pasta designada, para operar no documento ativo atual, por exemplo).

O primeiro script está localizado em:

/Users/<username>/Library/Application Support/TextWrangler/Scripts/

... e seu conteúdo é:

#!/usr/bin/php
<?php
    var_dump( $_SERVER );
    chdir( __DIR__ );
    $file = realpath( '../Unix Support/test.php' );
    exec( sprintf( 'open -a Terminal "%s" &', $file ) );
    exit( 0 );
?>

O segundo está em:

/Users/<username>/Library/Application Support/TextWrangler/Unix Support/

... e seu conteúdo é:

#!/usr/bin/php
<?php
    var_dump( $_SERVER );
    exit( 0 );
?>

O TextWrangler passa algumas variáveis de ambiente para o primeiro script (que eu posso acessar através de $_SERVER ), e elas são as esperadas. Por exemplo, o caminho correto para o documento atual que está ativo no TextWrangler.

Na primeira vez que executo o script, as variáveis de ambiente são automaticamente passadas corretamente para o segundo script (que abro com exec() ) também.

Agora vem a parte frustrante: quando eu troco o documento ativo no TextWrangler e executo o script novamente, o primeiro script recebe as variáveis de ambiente corretas do TextWrangler novamente, mas o segundo script ainda tem as variáveis de ambiente antigas, a menos que Eu matei o Terminal de antemão. Então, obviamente, a sessão do Terminal de alguma forma lembra as primeiras variáveis de ambiente e não quer atualizar.

Mas além de um entendimento muito básico, não tenho a menor idéia de como as variáveis de ambiente passam, de que escopo elas têm, etc. Então, alguém poderia explicar como eu posso fazer isso (se possível, começar com) que o segundo script recebe as variáveis de ambiente corretas novamente, sem ter que matar o Terminal toda vez?

Eu tentei definir explicitamente variáveis de ambiente no primeiro script antes de chamar exec() , assim:

foreach( $_SERVER as $key => $value )
{
    putenv( "$key=$value" );
}
exec( ... etc. );

Eu tentei não configurar as variáveis de ambiente no final, tanto no primeiro quanto no segundo script, assim:

foreach( $_SERVER as $key => $value )
{
    putenv( "$key" );
}

Mas nada funciona como eu esperava. Qualquer novo insight totalmente apreciado.

edit:

Nesse meio tempo, encontrei uma solução alternativa, mas insatisfatória: quando eu chamo open -n -a Terminal ... (observe o argumento -n adicionado) com exec() , ele inicia uma nova sessão do Terminal a cada vez, com o ambiente correto variáveis. Mas isso abre uma instância do Terminal completamente nova a cada vez.

update:

Eu simplifiquei o processo apenas usando um script em vez de dois agora, testando a variável de ambiente SHLVL . Eu também consegui acabar com uma nova instância do Terminal agora, usando um arquivo temporário, como Scott sugeriu também. Isso resultou no seguinte. Mas ainda sinto que não é muito elegante.

$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" );
    }
}

Ainda estou abrindo outras sugestões (além do CLI e sugestões de arquivos que o Scott já propôs). A menos, é claro, simplesmente não é possível (Scott pareceu sugerir isso já).

    
por Decent Dabbler 11.11.2013 / 22:58

1 resposta

1

Você já usou o Microsoft Office (Word, Excel e PowerPoint)? Você já abriu dois documentos / pastas de trabalho / apresentações ao mesmo tempo? Você notou que normalmente você só obtém um único processo da ferramenta apropriada, mesmo que tenha duas janelas? É bem claro que isso, ou algo bem parecido, é o que está acontecendo com o Terminal - a segunda solicitação open está sendo manipulada pelo processo que foi criado pela primeira open e está sendo tratada sem criar um novo processo. . Eu acho que open detecta que o processo já existe, e apenas envia uma mensagem para ele, em vez de criar um novo processo, ou algo assim.

Quanto à sua outra pergunta: as variáveis de ambiente são transmitidas do processo pai para o processo filho (ou seja, após a criação de um novo processo através de fork ) e são preservadas em exec chamadas. Assim, eles descem a hierarquia do processo, até que um processo saia ou explicitamente altere uma variável. Então, parece que o primeiro open causa fork e exec do Terminal, passando o ambiente, enquanto o segundo open apenas envia uma mensagem para o processo existente para executar ../Unix Support/test.php novamente, e o ambiente não é passado. Você parece ter encontrado as únicas maneiras de implementar a funcionalidade que deseja usando o ambiente - forçar a criação de um novo processo todas as vezes. Outras abordagens envolveriam passar os dados necessários por outros meios, como a linha de comando ou um arquivo.

    
por 12.11.2013 / 02:22