Qual é a diferença entre 'env' e 'printenv'?

67

Qual é a diferença entre os dois comandos enve printenv? Ambos mostram as variáveis ​​de ambiente e a saída é exatamente a mesma, exceto por _.

Existem razões históricas para haver dois comandos em vez de um?

WiSaGaN
fonte

Respostas:

49

Existem razões históricas para haver dois comandos em vez de um?

Havia apenas uma maneira histórica.

  1. Bill Joy escreveu a primeira versão do printenvcomando em 1979 para o BSD.
  2. O UNIX System III introduziu o envcomando em 1980.
  3. O GNU seguiu os sistemas UNIX envem 1986.
  4. O BSD seguiu os sistemas GNU / UNIX envem 1988.
  5. O MINIX seguiu o BSD printenvem 1988.
  6. O GNU seguiu o MINX / BSD's printenvem 1989.
  7. Utilitários de programação shell GNU 1.0 incluídos printenve envem 1991.
  8. O GNU Shell Utilities se fundiu com o GNU coreutils em 2002, o que você pode encontrar facilmente no GNU / Linux atualmente.

Observe que o "seguido" não significa que o código fonte era o mesmo, provavelmente eles foram reescritos para evitar processos de licença.

Portanto, a razão pela qual os dois comandos existiram é porque, quando Bill Joy escreveu printenvesse tempo, o envainda não existe. Após 10 anos de fusão / compatibilidade e o GNU, agora você está vendo os dois comandos semelhantes na mesma página.

Esse histórico é indicado da seguinte forma: (tento minimizar a resposta e fornecer apenas 2 códigos fonte essenciais aqui, o restante você pode clicar nos links anexados para ver)

[outono de 1975]

Também chegaram no outono de 1975 dois estudantes de pós-graduação despercebidos, Bill Joy e Chuck Haley; ambos se interessaram imediatamente pelo novo sistema. Inicialmente, eles começaram a trabalhar em um sistema Pascal que Thompson havia hackeado enquanto andava pela sala de máquinas 11/70.

[1977]

Joy começou a compilar o primeiro Berkeley Software Distribution (1BSD), lançado em 9 de março de 1978. // rf: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution

[Fevereiro de 1979]

1979 (veja "Bill Joy, UCB, fevereiro de 1979") / 1980 (veja "copyright [] ="), printenv.c // rf: http://minnie.tuhs.org/cgi-bin/utree.pl? file = 2.11BSD / src / ucb / printenv.c

/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
 All rights reserved.\n";
#endif not lint

#ifndef lint
static char sccsid[] = "@(#)printenv.c  5.1 (Berkeley) 5/31/85";
#endif not lint

/*
 * printenv
 *
 * Bill Joy, UCB
 * February, 1979
 */

extern  char **environ;

main(argc, argv)
    int argc;
    char *argv[];
{
    register char **ep;
    int found = 0;

    argc--, argv++;
    if (environ)
        for (ep = environ; *ep; ep++)
            if (argc == 0 || prefix(argv[0], *ep)) {
                register char *cp = *ep;

                found++;
                if (argc) {
                    while (*cp && *cp != '=')
                        cp++;
                    if (*cp == '=')
                        cp++;
                }
                printf("%s\n", cp);
            }
    exit (!found);
}

prefix(cp, dp)
    char *cp, *dp;
{

    while (*cp && *dp && *cp == *dp)
        cp++, dp++;
    if (*cp == 0)
        return (*dp == '=');
    return (0);
}

[1979]

Difícil de determinar lançado em 2BSD OU 3BSD // rf: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution

[Junho de 1980]

UNIX Release 3.0 OU "UNIX System III" // rf: ftp://pdp11.org.ru/pub/unix-archive/PDP-11/Distributions/usdl/SysIII/

[xiaobai@xiaobai pdp11v3]$ sudo grep -rni printenv . //no such printenv exist.
[xiaobai@xiaobai pdp11v3]$ sudo find . -iname '*env*'
./sys3/usr/src/lib/libF77/getenv_.c
./sys3/usr/src/lib/libc/vax/gen/getenv.c
./sys3/usr/src/lib/libc/pdp11/gen/getenv.c
./sys3/usr/src/man/man3/getenv.3c
./sys3/usr/src/man/docs/c_env
./sys3/usr/src/man/docs/mm_man/s03envir
./sys3/usr/src/man/man7/environ.7
./sys3/usr/src/man/man1/env.1
./sys3/usr/src/cmd/env.c
./sys3/bin/env
[xiaobai@xiaobai pdp11v3]$ man ./sys3/usr/src/man/man1/env.1 | cat //but got env already
ENV(1)                                                                General Commands Manual                                                                ENV(1)



NAME
       env - set environment for command execution

SYNOPSIS
       env [-] [ name=value ] ...  [ command args ]

DESCRIPTION
       Env obtains the current environment, modifies it according to its arguments, then executes the command with the modified environment.  Arguments of the form
       name=value are merged into the inherited environment before the command is executed.  The - flag causes the inherited environment to be ignored  completely,
       so that the command is executed with exactly the environment specified by the arguments.

       If no command is specified, the resulting environment is printed, one name-value pair per line.

SEE ALSO
       sh(1), exec(2), profile(5), environ(7).



                                                                                                                                                             ENV(1)
[xiaobai@xiaobai pdp11v3]$ 
[xiaobai@xiaobai pdp11v3]$ cat ./sys3/usr/src/cmd/env.c //diff with http://minnie.tuhs.org/cgi-bin/utree.pl?file=pdp11v/usr/src/cmd/env.c version 1.4, you will know this file is slightly older, so we can concluded that this file is "env.c version < 1.4"
/*
 *      env [ - ] [ name=value ]... [command arg...]
 *      set environment, then execute command (or print environment)
 *      - says start fresh, otherwise merge with inherited environment
 */
#include <stdio.h>

#define NENV    100
char    *newenv[NENV];
char    *nullp = NULL;

extern  char **environ;
extern  errno;
extern  char *sys_errlist[];
char    *nvmatch(), *strchr();

main(argc, argv, envp)
register char **argv, **envp;
{

        argc--;
        argv++;
        if (argc && strcmp(*argv, "-") == 0) {
                envp = &nullp;
                argc--;
                argv++;
        }

        for (; *envp != NULL; envp++)
                if (strchr(*envp, '=') != NULL)
                        addname(*envp);
        while (*argv != NULL && strchr(*argv, '=') != NULL)
                addname(*argv++);

        if (*argv == NULL)
                print();
        else {
                environ = newenv;
                execvp(*argv, argv);
                fprintf(stderr, "%s: %s\n", sys_errlist[errno], *argv);
                exit(1);
        }
}

addname(arg)
register char *arg;
{
        register char **p;

        for (p = newenv; *p != NULL && p < &newenv[NENV-1]; p++)
                if (nvmatch(arg, *p) != NULL) {
                        *p = arg;
                        return;
                }
        if (p >= &newenv[NENV-1]) {
                fprintf(stderr, "too many values in environment\n");
                print();
                exit(1);
        }
        *p = arg;
        return;
}

print()
{
        register char **p = newenv;

        while (*p != NULL)
                printf("%s\n", *p++);
}

/*
 *      s1 is either name, or name=value
 *      s2 is name=value
 *      if names match, return value of s2, else NULL
 */

static char *
nvmatch(s1, s2)
register char *s1, *s2;
{

        while (*s1 == *s2++)
                if (*s1++ == '=')
                        return(s2);
        if (*s1 == '\0' && *(s2-1) == '=')
                return(s2);
        return(NULL);
}
[xiaobai@xiaobai pdp11v3]$

[1985]

Manual do BSD first printenv // rf: http://minnie.tuhs.org/cgi-bin/utree.pl?file=2.11BSD/src/man/man1/printenv.1 mas não consigo encontrar o manual relacionado ao env , o mais próximo é getenv e environment // http://minnie.tuhs.org/cgi-bin/utree.pl?file=2.11BSD/src/man

[1986]

Primeira versão do GNU env// rf: ftp://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/env.c

[1987]

MINIX 1st lançado // rf: https://en.wikipedia.org/wiki/Andrew_S._Tanenbaum

  • Tanenbaum escreveu um clone do UNIX, chamado MINIX (MINi-unIX), para o PC IBM. Ele era direcionado a estudantes e outras pessoas que queriam aprender como um sistema operacional funcionava.

[1988]

BSD 1st env.c // http://minnie.tuhs.org/cgi-bin/utree.pl?file=2.11BSD/src/usr.sbin/cron/env.c

/* Copyright 1988,1990,1993,1994 by Paul Vixie
 * All rights reserved

[4 de outubro de 1988]

MINIX versão 1.3 // rf: https://groups.google.com/forum/#!topic/comp.os.minix/cQ8kaiq1hgI

... 32932 190 /minix/commands/printenv.c //printenv.c já existe

// rf: http://www.informatica.co.cr/linux/research/1990/0202.htm

[1989]

Primeira versão do GNU printenv, consulte [12 de agosto de 1993].

[16 de julho de 1991]

"Shellutils" - Utilitários de programação de shell GNU 1.0 lançados // rf: https://groups.google.com/forum/#!topic/gnu.announce/xpTRtuFpNQc

Os programas neste pacote são:

nome da base data dirname env expr grupos id logname pathchk printenv printf sleep tee tty whoami sim nice nohup stty uname

[12 de agosto de 1993]

printenv.c // rf: ftp://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/printenv.c

, GNU Shell Utilities 1.8 // rf: ftp://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/VERSION

/* printenv -- print all or part of environment
   Copyright (C) 1989, 1991 Free Software Foundation.
...

[1993]

printenv.c, encontrado no código-fonte do DSLinux em 2006 // rf: (Google) cache: mailman.dslinux.in-berlin.de/pipermail/dslinux-commit-dslinux.in-berlin.de/2006-August/000578. html

--- NEW FILE: printenv.c ---
/*
 * Copyright (c) 1993 by David I. Bell

[Novembro de 1993]

A primeira versão do FreeBSD foi lançada. // rf: https://en.wikipedia.org/wiki/FreeBSD

[1 de setembro de 2002]

http://git.savannah.gnu.org/cgit/coreutils.git/tree/README-package-renamed-to-coreutils

Os pacotes GNU fileutils, textutils e sh-utils (consulte "Shellutils" em 16 de julho de 1991 acima) foram combinados em um, chamado GNU coreutils.

No geral, os envcasos de uso são comparados com printenv:

  1. imprime variáveis ​​de ambiente, mas printenvpode fazer o mesmo
  2. Desative o shell interno, mas também pode ser alcançado com o enablecmd.
  3. definir variável, mas sem sentido devido a algumas conchas já pode fazê-lo sem env, por exemplo,

    $ HOME = / dev HOME = / tmp USUÁRIO = root / bin / bash -c "cd ~; pwd"

    / tmp

  4. #!/usr/bin/env pythoncabeçalho, mas ainda não é portátil se envnão estiver em / usr / bin

  5. env -i, desative todos os env. Achei útil descobrir as variáveis ​​críticas de ambiente de um determinado programa para executá-lo crontab. por exemplo [1] No modo interativo, execute declare -p > /tmp/d.shpara armazenar variáveis ​​de atributos. [2] Em /tmp/test.sh, escreva: . /tmp/d.sh; eog /home/xiaobai/Pictures/1.jpg[3] Agora execute env -i bash /tmp/test.sh[4] Se conseguir exibir imagem, remova metade das variáveis /tmp/d.she execute env -i bash /tmp/test.shnovamente. Se algo falhar, desfaça-o. Repita o passo para diminuir. [5] Finalmente, eu descobri que é eognecessário $DISPLAYexecutar o processo crontabe, na ausência de $DBUS_SESSION_BUS_ADDRESS, diminuirá a exibição da imagem.

  6. target_PATH="$PATH:$(sudo printenv PATH)";é útil direcionar o uso do caminho raiz sem precisar analisar ainda mais a saída de envou printenv.

por exemplo:

xb@dnxb:~$ sudo env | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
xb@dnxb:~$ sudo printenv | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
xb@dnxb:~$ sudo printenv PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
xb@dnxb:~$ sudo env PATH
env: ‘PATH’: No such file or directory
xb@dnxb:~$
林果 皞
fonte
4
Boa lição de história.
Ouki
21

Tendo um ponto de vista diferente (do FreeBSD), você tem:

De man env:

 The env utility executes another utility after modifying the environment
 as specified on the command line.  Each name=value option specifies the
 setting of an environment variable, name, with a value of value.  All
 such environment variables are set before the utility is executed.
 ...
 If no utility is specified, env prints out the names and values of the
 variables in the environment, with one name/value pair per line.

De man printenv:

 The printenv utility prints out the names and values of the variables in
 the environment, with one name/value pair per line.  If name is speci-
 fied, only its value is printed.

Portanto, esses comandos podem ter o mesmo efeito sem argumento, mas o printenvúnico objetivo é exibir a chave / valores do ambiente atual, enquanto o envobjetivo é definir algum ambiente antes de chamar outro binário / script / qualquer coisa.

É mais claro assim?

Para saber mais:

Ouki
fonte
2
Pelos links fornecidos: O envcomando apareceu no 4.4BSD. As opções -P, -S e -v foram adicionadas no FreeBSD 6.0. O printenvcomando apareceu no 3.0BSD. Então a razão histórica parece ser a que printenvchegou primeiro.
Mcmlxxxvi
3

Nas páginas de manual:

env - executa um programa em um ambiente modificado

...

printenv - imprime todo ou parte do ambiente

Deve ser bem explicativo.

UVV
fonte
4
mas eu não entendo ...
mikeserv
Suponho que env vem antes de printenv. Então, por que fazer outro binário? Não é o mesmo com o que 'll' para 'ls', pois 'll' não é um binário e não possui uma página de manual.
WiSaGaN
O @mikeserv printenvapenas imprime todas as variáveis ​​do ambiente atual. Com envvocê, você pode preparar o mesmo ambiente com algumas modificações, se necessário, e executar um aplicativo nele.
UVV
@WiSaGaN sua comparação não está realmente correta. lsé um binário, mas llé um alias comum, que geralmente se expande para ls -l. printenve envexistem dois binários diferentes, embora não tenha certeza de qual deles foi apresentado primeiro. Você pode ver mais alguns exemplos aqui: gnu.org/software/coreutils/manual/html_node/env-invocation.html
UVV
11
@mikeserv, veja o texto do mouse sobre este quadrinho . :)
Caractere curinga
3

Falando estritamente sobre funcionalidades, envé um binário com um enorme conjunto de recursos, um deles imprimindo variáveis ​​de ambiente, enquanto printenvapenas imprime variáveis ​​de ambiente.

Resumindo, se você está acostumado a trabalhar com env, você irá envimprimi-los (porque é isso que você está acostumado) e, se não estiver, normalmente se lembrará printenvmais rápido.

Praticamente não há diferenças quando se fala em printenvvs envapenas para imprimir variáveis ​​ambientais. Acabei de verificar e o ambiente é um pouco mais pesado (cerca de 5 KB extras), e o desempenho (com o tempo) parece exatamente o mesmo.

Espero que isso esclareça tudo! :)

David González Ruiz
fonte
-1

Se você realmente deseja saber o quão diferente é a saída dos dois binários, independentemente do histórico e do legado deles, você pode executar alguns utilitários para avaliar essa diferença. No debian, executei algumas coisas que serão diferentes, dependendo de quaisquer variáveis ​​ambientais personalizadas:

env |wc -l
printenv |wc -l

Tanto a minha saída tem 41 linhas

env > env.txt
printenv > printenv.txt
diff env.txt printenv.txt

Saída: 41c41 <_ = / usr / bin / env ---

_ = / usr / bin / printenv

Então você vê que há uma linha diferente nas duas e essa linha é o número 41, que eu acho que estipula o binário usado no comando. Sem argumentos adicionais, eles relatam informações idênticas virtuais para mim.

caçador
fonte