Respostas:
Existem razões históricas para haver dois comandos em vez de um?
Havia apenas uma maneira histórica.
printenv
comando em 1979 para o BSD.env
comando em 1980.env
em 1986.env
em 1988.printenv
em 1988.printenv
em 1989.printenv
e env
em 1991.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 printenv
esse tempo, o env
ainda 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
3BSD O comando printenv apareceu no 3.0 BSD. // rf: http://www.freebsd.org/cgi/man.cgi?query=printenv&sektion=1#end 3.0 BSD introduzido em 1979 // rf: http://gunkies.org/wiki/3_BSD
2BSD O comando printenv apareceu pela primeira vez em 2BSD // rf: http://man.openbsd.org/printenv.1
[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
[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 env
casos de uso são comparados com printenv
:
printenv
pode fazer o mesmoenable
cmd.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
#!/usr/bin/env python
cabeçalho, mas ainda não é portátil se env
não estiver em / usr / bin
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.sh
para 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.sh
e execute env -i bash /tmp/test.sh
novamente. Se algo falhar, desfaça-o. Repita o passo para diminuir. [5] Finalmente, eu descobri que é eog
necessário $DISPLAY
executar o processo crontab
e, na ausência de $DBUS_SESSION_BUS_ADDRESS
, diminuirá a exibição da imagem.
target_PATH="$PATH:$(sudo printenv PATH)";
é útil direcionar o uso do caminho raiz sem precisar analisar ainda mais a saída de env
ou 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:~$
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 env
objetivo é definir algum ambiente antes de chamar outro binário / script / qualquer coisa.
É mais claro assim?
Para saber mais:
man 1 env
(FreeBSD)man 1 printenv
(FreeBSD)env
comando apareceu no 4.4BSD. As opções -P, -S e -v foram adicionadas no FreeBSD 6.0. O printenv
comando apareceu no 3.0BSD. Então a razão histórica parece ser a que printenv
chegou primeiro.
env
é o POSIX 7 ,printenv
não é (GNU Coreutils no Ubuntu 15.10).
Nas páginas de manual:
env - executa um programa em um ambiente modificado
...
printenv - imprime todo ou parte do ambiente
Deve ser bem explicativo.
printenv
apenas imprime todas as variáveis do ambiente atual. Com env
você, você pode preparar o mesmo ambiente com algumas modificações, se necessário, e executar um aplicativo nele.
ls
é um binário, mas ll
é um alias comum, que geralmente se expande para ls -l
. printenv
e env
existem 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
Falando estritamente sobre funcionalidades, env
é um binário com um enorme conjunto de recursos, um deles imprimindo variáveis de ambiente, enquanto printenv
apenas imprime variáveis de ambiente.
Resumindo, se você está acostumado a trabalhar com env, você irá env
imprimi-los (porque é isso que você está acostumado) e, se não estiver, normalmente se lembrará printenv
mais rápido.
Praticamente não há diferenças quando se fala em printenv
vs env
apenas 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! :)
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.