Como depurar variáveis ​​de ambiente no Linux

Muitas vezes acontece que você chega à máquina e encontra algum tipo de script em execução no usuário do sistema há uma semana. Quem o lançou? Onde procurar este run.php? Ou você adiciona uma entrada ao / etc / crontab e o script trava ali com o erro "comando não encontrado". Porque E o que fazer?

Eu tenho as respostas para essas perguntas.



Variáveis ​​de ambiente


Em quase todos os sistemas operacionais modernos, os processos têm variáveis ​​de ambiente. Tecnicamente, eles são uma coleção de cadeias nomeadas. Se um subprocesso for iniciado, ele herdará automaticamente uma cópia do ambiente do pai.

Entre outras, há a variável PATH, que indica os caminhos para procurar arquivos executáveis, a variável HOME, que indica o diretório inicial do usuário, as variáveis ​​responsáveis ​​pelas preferências de idioma do usuário e muitas outras.

Existem muitas revisões descrevendo o significado dessas variáveis, mas praticamente não existem artigos sobre como investigar problemas. Preencha esta lacuna.

Quem iniciou o processo?


Então, encontramos um script em execução no usuário do sistema há uma semana. Quem o lançou? Porque Talvez eles tenham esquecido dele? Potencialmente entre 10 e 15 pessoas podem lançá-lo, você não entrevista todos. Como descobrir quem era? E onde esse run.php está?

$ ps x | grep run.php 10684 ? Ss 472:25 /local/php/bin/php run.php 

As variáveis ​​de ambiente do processo e o recurso sudo são úteis. Existe uma variável PWD na qual o shell armazena o diretório de trabalho atual; esse valor, de fato, salva informações sobre o diretório atual no momento em que o comando é executado. Além disso, o utilitário sudo, por padrão, deixa informações na variável de ambiente do processo sobre qual usuário ele foi iniciado.

Variáveis ​​de ambiente (e muito mais) para qualquer processo em execução podem ser encontradas em / proc. Voila:

 $ cat /proc/10684/environ | tr '\0' '\n' | grep SUDO_USER SUDO_USER=alexxz $ cat /proc/10684/environ | tr '\0' '\n' | grep PWD PWD=/home/etlmaster 

Ahem, eu mesmo a lancei. Bem, quem não acontece?

Em geral, usando um método tão simples em situações simples, você pode encontrar informações sobre o processo, que geralmente não está disponível.

O script funciona na linha de comando, mas não funciona no cron


Um dos casos em que você precisa pensar em variáveis ​​de ambiente é quando um script adicionado ao / etc / crontab trava com um erro. Você vai ao servidor via SSH, executa o comando, tudo parece funcionar como deveria. E quando é iniciado automaticamente, mostra algo como "hive: command not found".

Em geral, é uma boa prática escrever o caminho completo para comandos executáveis, mas isso nem sempre é possível. Nesses casos, os desenvolvedores saem como qualquer um pode. Alguém adiciona o caminho desejado no PATH como parte da equipe do crontab. Os mais experientes envolvem seu comando no bash -l. E as bombas corvos ensinadas por uma experiência amarga ainda não esquecem de se reunir. Tudo é assim: feito, adicionado ao monitoramento e esquecido.

Após essas manipulações, um sedimento permanece na alma de um verdadeiro engenheiro. Sim, o problema está resolvido. Mas eu não entendi o que estava acontecendo! Como uma abordagem é melhor que outra? Onde todas essas configurações são armazenadas e por quem elas são alteradas?

Vamos comparar as variáveis ​​de ambiente que o processo possui quando é iniciado a partir da coroa e as variáveis ​​de ambiente que temos na linha de comando. Registramos a saída do comando env da coroa e nosso ambiente atual:

 $ echo "* * * * * env > ~/crontab.env" | crontab; sleep 60; echo "" | crontab; $ env > my.env 

Veja o que está na variável PATH:

 > grep ^PATH= crontab.env my.env Crontab.env: PATH=/usr/bin:/bin My.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/local/hadoop/bin:/usr/local/bin:/usr/bin:/bin 



Mama Mia! Então, sob a coroa apenas o mínimo! Obviamente, você precisa carregar as variáveis ​​de ambiente normais.

Vamos ver qual será o ambiente se adicionarmos bash -l:

 $ echo "* * * * * bash -l env > ~/crontab.env" | crontab; sleep 60; echo "" | crontab; alexxz@bi1.mlan:~> grep ^PATH= crontab.env my.env Crontab.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/usr/local/bin:/usr/bin:/bin My.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/local/hadoop/bin:/usr/local/bin:/usr/bin:/bin 

A diferença não é tão perceptível. Todos os caminhos são apresentados. Alguns em uma ordem diferente, outros são repetidos, mas isso já é muito melhor do que era. O restante das variáveis ​​também está bem ajustado. Obviamente, há uma pequena diferença no local, nas variáveis ​​do SSH, mas isso não deve mais afetar drasticamente a operação do script.

Agora está claro por que bash -l é necessário nas entradas do crontab. E, claro, não se esqueça do rebanho.

Inicialização de depuração de scripts de logon


O problema parece estar resolvido, tudo da coroa funciona. Mas como é que alguns caminhos são duplicados na variável PATH? Portanto, há algum tipo de confusão na configuração do servidor. Vamos tentar descobrir.

Abrimos um homem para inicializar o ambiente, lemos quais scripts e em que ordem são executados, com entusiasmo começamos a passar por seus olhos - e depois de alguns minutos surge uma sensação de desespero. Algum fluxo interminável de condições sobre alguns casos especiais de arquiteturas, terminais e configurações de cores incrivelmente importantes para o comando ls. Dor, desespero, ódio! Estamos interessados ​​em uma maldita variável PATH!

De fato, tudo é um pouco mais simples. Conheça:

 env -i bash -x -l -c 'echo 123' > login.log 2>&1 

O que essa equipe faz? Cria um novo processo bash com um ambiente puro, indica que é necessário executar scripts de inicialização e proteger tudo em detalhes no arquivo login.log. Agora temos a oportunidade de não executar todos os scripts em nossa mente, mas simplesmente ler o que, onde e quando foi executado e de onde veio esse ou aquele ambiente.

Não analisarei em detalhes como ler o log resultante. Tudo é quase trivial lá. Mencionei apenas que um hit veio de / etc / profile e dois de /etc/bash.bashrc. Sim, em algum lugar eles eram muito inteligentes ao montar pacotes em um pappet. Bem, nada, não me incomoda trabalhar.

Mas agora eu sei e posso!

PS Em casos muito difíceis e para entender tudo, você pode agrupar o comando em strace:

  strace -f env -i bash -x -l -c 'echo 123' > login.log 2>&1 

Source: https://habr.com/ru/post/pt465021/


All Articles