env -i zsh | Como esta magia é possível?

3

Atualmente estou trabalhando, para a escola, em um shell caseiro, portanto estou curioso hoje em dia sobre como os shell vars são definidos. Sim, isso pode ser muito emocionante!

De qualquer forma, obviamente temos que lidar com o caso quando nosso shell será lançado com um ambiente vazio, ou seja, o comando "env -i". Com env -i, a variável externa environ está absolutamente vazia, então temos que nos construir um PATH básico, PWD e tudo mais.

Nossa referência é csh, porque é fácil e simples. Quando você iniciar o csh com env -i e, em seguida, imprimir suas variáveis, veja o que você pode ver:

$ env -i csh
% set
addsuffix
argv    ()
csubstnonl
cwd /Users/noesierra-velasquez
dirstack    /Users/noesierra-velasquez
echo_style  bsd
edit
gid 20
group   staff
history 100
killring    30
owd
path    (/usr/bin /bin)
prompt  %
prompt2 %R?
prompt3 CORRECT>%R (y|n|e|a)?
shell   /bin/tcsh
shlvl   1
status  0
tcsh    6.17.00
tty ttys001
uid 501
user    noesierra-velasquez
version tcsh 6.17.00 (Astron) 2009-07-10 (x86_64-apple-darwin) options         wide,nls,dl,al,kan,sm,rh,color,filec
% env
HOSTTYPE=intel-mac
VENDOR=apple
OSTYPE=darwin
MACHTYPE=x86_64
SHLVL=1
PWD=/Users/noesierra-velasquez
LOGNAME=noesierra-velasquez
USER=noesierra-velasquez
GROUP=staff
HOST=MacBook-Pro-de-Noe-Sierra-Velasquez.local
REMOTEHOST=

Ok, então, como você pode ver, não há um conjunto HOME e me parece absolutamente normal. Se você digitar cd , receberá cd: No home directory. . Nós vivemos em um mundo normal.

Mas aqui está a mágica. Digite, dentro do seu vazio csh env -i zsh . zsh será carregado. Agora imprima todas as variáveis de env. (Nota: funciona perfeitamente se você digitar diretamente env -i zsh , mesmo de dentro de zsh, eu faço isso aqui desta forma, só para ter certeza absoluta de que não há nenhum truque complicado com zsh chamando a si mesmo ou o que for)

% env -i zsh
$ env
HOME=/Users/noesierra-velasquez
LOGNAME=noesierra-velasquez
SHLVL=1
PWD=/Users/noesierra-velasquez
OLDPWD=/Users/noesierra-velasquez
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
_=/usr/bin/env

Uau! O que aconteceu !? zsh parece ter (e fez) uma maneira de recuperar $ HOME e $ OLDPWD do que me parece ser o nada puro. (btw se alguém não sabe, eu tenho certeza que ele usa paths.h para voltar seu caminho).

Obviamente eu sei que o "nada puro" não é uma possibilidade viável, então estou perguntando a vocês: Você sabe como o zsh está voltando para o HOME e o OLDPWD?

Obrigado pela sua paciência e tenha um bom dia! :)

    
por nsierra- 15.02.2014 / 02:42

2 respostas

1
  1. A documentação diz o seguinte sobre a variável $HOME :

    HOME <S> The default argument for the cd command. This is not set automatically by the shell in sh, ksh or csh emulation, but it is typically present in the environment anyway, and if it becomes set it has its usual special behaviour.

    Eu li o contrário, quando zsh é invocado por si só, ele reúne as informações sobre o homedir do gerenciamento de usuários do sistema. Este snippet (incompleto) (de Src/init.c ) serve como prova:

    /* Get password entry and set info for 'USERNAME' */
    if ((pswd = getpwuid(cached_uid))) {
        if (EMULATION(EMULATE_ZSH))
            home = metafy(pswd->pw_dir, -1, META_DUP);
    ...
    /*
    Try a cheap test to see if we can initialize 'PWD' from 'HOME'.
    In non-native emulations HOME must come from the environment;
    we're not allowed to set it locally.
    */
    if (EMULATION(EMULATE_ZSH))
      ptr = home;
    else
      ptr = zgetenv("HOME");
    ...

    Portanto, sem emulação (ou seja, "emular zsh"), o homedir é determinado pela chamada do sistema getpwuid . Somente de outra forma, o $HOME do ambiente é usado.

  2. Não consigo reproduzir sua "mágica" com $PWD e $OLDPWD . Mas talvez você deva considerar invocar zsh como zsh -f , para que nenhuma configuração de usuário (zsh conheça seu homedir!) E de todo o sistema seja obtida. Com esse comando eu recebo o seguinte ambiente em uma caixa debian:

    $ pwd
    /tmp
    $ env -i zsh -f
    jessie% env
    HOME=/home/user
    LOGNAME=user
    SHLVL=1
    PWD=/tmp
    OLDPWD=/tmp
    _=/usr/bin/env
    jessie% 

    Portanto, não há valores surpreendentes de $PWD e $OLDPWD . O código-fonte que define esses parâmetros segue diretamente para o código acima:

    else if ((ptr = zgetenv("PWD")) && (strlen(ptr) < PATH_MAX) &&
        (ptr = metafy(ptr, -1, META_STATIC), ispwd(ptr)))
        pwd = ztrdup(ptr);
     else {
        pwd = NULL;
        pwd = metafy(zgetcwd(), -1, META_DUP);
     }
    
    

    oldpwd = ztrdup(pwd); /* initialize OLDPWD' =PWD' */

    Portanto, se $HOME não for definido no ambiente, uma função zgetcwd será usada. Eu não rastreei isso, mas aposto, ele retorna o diretório de trabalho atual ;) . Finalmente $OLDPWD é inicializado com o mesmo valor.

Todos os exemplos e trechos de código são tirados de zsh 5.0.5-dev-0

    
por 15.02.2014 / 18:31
0

Obrigado pela preciosa informação. Isso me ajudou muito a entender como tudo funciona.

No entanto, eu fundei uma solução simples para recuperar $ HOME mesmo quando env for nul (como fazia parte da minha tarefa). O programa a seguir funciona como um encanto e usa um sinalizador NON-POSIX da função glob (3) (portanto, tenha cuidado ao verificar se existe em glob.h ).

#include <stdio.h>
#include <glob.h>

int                 main(void)
{
    glob_t          glob_info;
    unsigned int    i;
    int             ret;

    i = 0;
    if (!(ret = glob("~", GLOB_TILDE, NULL, &glob_info)))
    {
        while (i < glob_info.gl_pathc)
            printf("%s\n", glob_info.gl_pathv[i++]);
    }
    else
        printf("Glob error : %d\n", ret);
    return (0);
}

Por favor, note que glob(3) é não feita originalmente para este fim.

    
por 11.03.2014 / 03:35