Odpowiedzi:
Czy są jakieś historyczne powody, dla których istnieją dwa polecenia zamiast jednego?
Był tylko sposób historyczny.
printenv
polecenia w 1979 r. Dla BSD.env
polecenie w 1980 roku.env
w 1986 roku.env
w 1988 roku.printenv
w 1988 roku.printenv
w 1989 roku.printenv
oraz env
w 1991 roku.Zauważ, że „obserwowane” nie oznacza, że kod źródłowy był taki sam, prawdopodobnie zostały przepisane w celu uniknięcia procesu licencyjnego.
Powodem, dla którego istniały oba polecenia, jest to, że kiedy Bill Joy napisał printenv
ten czas, env
jeszcze nie istnieje. Po 10 latach scalania / kompatybilności i GNU natrafisz na to, teraz widzisz oba podobne polecenia na tej samej stronie.
Historia ta wskazuje, co następuje: (Staram się zminimalizować odpowiedź, dlatego podaje tylko 2 niezbędne kody źródłowe, resztę możesz kliknąć w załączone linki, aby zobaczyć)
[jesień 1975]
Jesienią 1975 r. Przybyli także dwaj niezauważeni absolwenci, Bill Joy i Chuck Haley; oboje natychmiast zainteresowali się nowym systemem. Początkowo rozpoczęli pracę nad systemem Pascal, który Thompson zhakował razem, kręcąc się po maszynowni 11/70.
[1977]
Joy zaczął kompilować pierwszą Berkeley Software Distribution (1BSD), która została wydana 9 marca 1978 r. // rf: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution
[Luty 1979]
1979 (patrz „Bill Joy, UCB luty 1979”) / 1980 (patrz „copyright [] =”), printenv.c // rf: http://minnie.tuhs.org/cgi-bin/utree.pl? plik = 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]
Trudno ustalić, wydany w 2BSD LUB 3BSD // rf: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution
3BSD Polecenie printenv pojawiło się w 3.0 BSD. // rf: http://www.freebsd.org/cgi/man.cgi?query=printenv&sektion=1#end 3.0 BSD wprowadzony w 1979 r. // rf: http://gunkies.org/wiki/3_BSD
2BSD Komenda printenv pojawiła się po raz pierwszy w 2BSD // rf: http://man.openbsd.org/printenv.1
[Czerwiec 1980]
UNIX Release 3.0 LUB „UNIX System III” // rf: ftp://pdp11.org.ru/pub/unix-archive/PDP-11/Distribution/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]
BSD pierwsza instrukcja printenv // rf: http://minnie.tuhs.org/cgi-bin/utree.pl?file=2.11BSD/src/man/man1/printenv.1, ale nie mogę znaleźć instrukcji związanej z env , najbliższy jest getenv i environment // http://minnie.tuhs.org/cgi-bin/utree.pl?file=2.11BSD/src/man
[1986]
Pierwsza wersja GNU env
// rf: ftp://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/env.c
[1987]
Wydano MINIX 1st // 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 października 1988 r.]
Wersja MINIX 1.3 // rf: https://groups.google.com/forum/#!topic/comp.os.minix/cQ8kaiq1hgI
... 32932 190 /minix/commands/printenv.c //printenv.c już istnieje
// rf: http://www.informatica.co.cr/linux/research/1990/0202.htm
[1989]
Pierwsza wersja GNU printenv
, patrz [12 sierpnia 1993].
[16 lipca 1991 r.]
„Shellutils” - udostępniono narzędzia do programowania powłoki GNU 1.0 // rf: https://groups.google.com/forum/#!topic/gnu.announce/xpTRtuFpNQc
Programy w tym pakiecie to:
data basename dirname env grupy expr id LOGNAME pathchk printenv printf sen tee tty whoami tak miły nohup stty uname
[12 sierpnia 1993 r.]
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, który znalazł w kodzie źródłowym DSLinux w 2006 r. // rf: pamięć podręczna (Google): 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
[Listopad 1993]
Pierwsza wersja FreeBSD została wydana. // rf: https://en.wikipedia.org/wiki/FreeBSD
[1 września 2002 r.]
http://git.savannah.gnu.org/cgit/coreutils.git/tree/README-package-renamed-to-coreutils
Paczki plików GNU, textutils i sh-utils (patrz „Shellutils” 16 lipca 1991 r. Powyżej) zostały połączone w jeden, zwany coreutils GNU.
Ogólnie env
przypadki użycia porównują z printenv
:
printenv
może zrobić to samoenable
cmd.ustaw zmienną, ale bez sensu, ponieważ niektóre powłoki już mogą to zrobić bez env
, np
$ HOME = / dev HOME = / tmp USER = root / bin / bash -c "cd ~; pwd"
/ tmp
#!/usr/bin/env python
nagłówek, ale nadal nie jest przenośny, jeśli env
nie znajduje się w / usr / bin
env -i
, wyłącz wszystkie środowiska. Uznałem, że przydatne jest ustalenie krytycznych zmiennych środowiskowych dla niektórych programów, z których można je uruchomić crontab
. np. [1] W trybie interaktywnym uruchom, declare -p > /tmp/d.sh
aby zapisać zmienne atrybutów. [2] W /tmp/test.sh
, napisz: . /tmp/d.sh;
eog /home/xiaobai/Pictures/1.jpg
[3] Teraz uruchom env -i bash /tmp/test.sh
[4] Jeśli wyświetlanie obrazu się powiedzie, usuń połowę zmiennych /tmp/d.sh
i uruchom env -i bash /tmp/test.sh
ponownie. Jeśli coś się nie powiedzie, cofnij to. Powtórz krok w celu zawężenia. [5] Wreszcie stwierdziłem, że eog
wymaga $DISPLAY
wbiegania crontab
, a nieobecność $DBUS_SESSION_BUS_ADDRESS
spowolni wyświetlanie obrazu.
target_PATH="$PATH:$(sudo printenv PATH)";
jest użyteczny do bezpośredniego użycia ścieżki katalogu głównego bez konieczności dalszego analizowania danych wyjściowych env
lub printenv
.
na przykład:
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:~$
Mając inny punkt widzenia (z FreeBSD), masz:
Od 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.
Od 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.
Więc te polecenia mogą mieć ten sam efekt bez argumentów, ale printenv
jedynym celem jest wyświetlenie bieżącego klucza / wartości środowiska, a env
celem jest ustawienie jakiegoś środowiska przed wywołaniem innego pliku binarnego / skryptu / cokolwiek.
Czy w ten sposób jest to bardziej jasne?
Aby wiedzieć więcej:
man 1 env
(FreeBSD)man 1 printenv
(FreeBSD)env
printenv
printenv
env
jest POSIX 7 ,printenv
nie jest (GNU Coreutils w Ubuntu 15.10).
Ze stron podręcznika:
env - uruchom program w zmodyfikowanym środowisku
...
printenv - wydrukuj całość lub część środowiska
Powinno być dość objaśniające.
printenv
po prostu drukuje wszystkie zmienne bieżącego środowiska. Dzięki env
możesz przygotować to samo środowisko z pewnymi modyfikacjami, jeśli to konieczne, i uruchomić w nim aplikację.
ls
jest plikiem binarnym, ale ll
jest popularnym aliasem, który zwykle po prostu się rozwija ls -l
. printenv
i env
są to dwa różne pliki binarne, nie jestem jednak pewien, który został wprowadzony jako pierwszy. Możesz zobaczyć więcej przykładów tutaj gnu.org/software/coreutils/manual/html_node/env-invocation.html
Mówiąc ściśle o funkcjonalnościach, env
jest to plik binarny z ogromnym zestawem funkcji, jedną z nich jest drukowanie zmiennych środowiskowych, podczas gdy printenv
tylko drukowanie zmiennych środowiskowych.
Podsumowując, jeśli jesteś przyzwyczajony do pracy z env, pójdziesz z env
drukowaniem ich (ponieważ do tego jesteś przyzwyczajony), a jeśli nie, zazwyczaj będziesz pamiętać printenv
szybciej.
Nie ma praktycznie żadnych różnic, gdy mówimy o printenv
vs env
tylko do drukowania zmiennych środowiskowych. Właśnie sprawdziłem, a env jest nieco cięższy (około 5 dodatkowych KB), a ich wydajność (w czasie) wydaje się dokładnie taka sama.
Mam nadzieję, że to wyjaśni! :)
Jeśli naprawdę chcesz wiedzieć, jak różne są dane wyjściowe dwóch plików binarnych, bez względu na ich historię i dziedzictwo, możesz uruchomić kilka narzędzi, aby ocenić tę różnicę. Na Debianie uruchomiłem kilka rzeczy, które będą się różnić w zależności od niestandardowych zmiennych środowiskowych:
env |wc -l
printenv |wc -l
Oba moje wyjście ma 41 linii
env > env.txt
printenv > printenv.txt
diff env.txt printenv.txt
Wyjście: 41c41 <_ = / usr / bin / env ---
_ = / usr / bin / printenv
Widzicie więc, że w obu jest jedna linia inna i ta linia ma numer 41, co, jak sądzę, określa plik binarny użyty w poleceniu. Bez dodatkowych argumentów raportują one dla mnie wirtualne identyczne informacje.