Ответы:
Существуют ли какие-либо исторические причины существования двух команд вместо одной?
Была только историческая манера.
printenvкоманды в 1979 году для BSD.envкоманду в 1980 году.envв 1986 году.envв 1988 году.printenvв 1988 году.printenvв 1989 году.printenvи envв 1991 году.Обратите внимание, что слово "follow" не означает, что исходный код был таким же, вероятно, они были переписаны, чтобы избежать судебного иска.
Таким образом, причина существования обеих команд заключается в том, что когда Билл Джой написал printenvэто время, его envеще не было. После 10 лет слияния / совместимости и GNU с этим столкнулись, теперь вы видите обе подобные команды на одной странице.
Эта история обозначается следующим образом: (Я стараюсь свести к минимуму ответ и поэтому здесь представлен только 2 основных исходных кода, остальные вы можете нажать на прикрепленные ссылки, чтобы увидеть)
[осень 1975 года]
Осенью 1975 года также прибыли двое незаметных аспирантов, Билл Джой и Чак Хейли; они оба сразу заинтересовались новой системой. Первоначально они начали работать над системой Pascal, которую Томпсон взломал вместе, пока висел в машинном зале 11/70.
[1977]
Джой начал собирать первый дистрибутив программного обеспечения Berkeley (1BSD), который был выпущен 9 марта 1978 года. // rf: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution
[Февраль 1979 года]
1979 (см. «Bill Joy, UCB February, 1979») / 1980 (см. «Copyright [] =»), printenv.c // rf: http://minnie.tuhs.org/cgi-bin/utree.pl? файл = 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]
Трудно определить, выпущен в 2BSD ИЛИ 3BSD // rf: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution
3BSD Команда printenv появилась в 3.0 BSD. // rf: http://www.freebsd.org/cgi/man.cgi?query=printenv&sektion=1#end 3.0 BSD, выпущенный в 1979 году // rf: http://gunkies.org/wiki/3_BSD
2BSD Команда printenv впервые появилась в 2BSD // rf: http://man.openbsd.org/printenv.1
[Июнь 1980 года]
UNIX Release 3.0 ИЛИ «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]
Первое руководство BSD для печати // rf: http://minnie.tuhs.org/cgi-bin/utree.pl?file=2.11BSD/src/man/man1/printenv.1, но я не могу найти руководство, связанное с env наиболее близким является getenv и окружающая среда // http://minnie.tuhs.org/cgi-bin/utree.pl?file=2.11BSD/src/man
[1986]
Первая версия GNU env// rf: ftp://ftp-archive.freebsd.org/pub/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/env.c
[1987 год]
Выпущен первый MINIX // 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 октября 1988]
MINIX версии 1.3 // rf: https://groups.google.com/forum/#!topic/comp.os.minix/cQ8kaiq1hgI
... 32932 190 /minix/commands/printenv.c //printenv.c уже существует
// rf: http://www.informatica.co.cr/linux/research/1990/0202.htm
[1989]
Первая версия GNU printenv, см. [12 августа 1993].
[16 июля 1991 г.]
"Shellutils" - выпущены утилиты программирования оболочки GNU 1.0 // rf: https://groups.google.com/forum/#!topic/gnu.announce/xpTRtuFpNQc
Программы в этом пакете:
базовое имя дата dirname env expr группы id логин pathchk printenv printf sleep tee tty whoami да хороший nohup stty uname
[12 августа 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, найденный в исходном коде DSLinux в 2006 году // rf: (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
[Ноябрь 1993 г.]
Первая версия FreeBSD была выпущена. // rf: https://en.wikipedia.org/wiki/FreeBSD
[1 сентября 2002 г.]
http://git.savannah.gnu.org/cgit/coreutils.git/tree/README-package-renamed-to-coreutils
Пакеты GNU fileutils, textutils и sh-utils (см. «Shellutils» от 16 июля 1991 г. выше) были объединены в один, называемый GNU coreutils.
В целом, envварианты использования сравниваются с printenv:
printenvможно сделать то же самоеenablecmd.установить переменную, но бессмысленно, потому что некоторые оболочки уже могут делать это env, например,
$ HOME = / dev HOME = / tmp USER = root / bin / bash -c "cd ~; pwd"
/ TMP
#!/usr/bin/env pythonзаголовок, но все еще не переносимый, если envне в / usr / bin
env -i, отключить все env. Я нашел полезным выяснить критические переменные среды для определенной программы, из которой она запускается crontab. например, [1] В интерактивном режиме запустите declare -p > /tmp/d.shдля хранения атрибутов переменных. [2] В /tmp/test.sh, напишите: . /tmp/d.sh;
eog /home/xiaobai/Pictures/1.jpg[3] Теперь запустите env -i bash /tmp/test.sh[4] Если удачно отобразить изображение, удалите половину переменных /tmp/d.shи запустите env -i bash /tmp/test.shснова. Если что-то не получилось, отмените это. Повторите шаг, чтобы сузить. [5] Наконец-то я понял, что eogнужно $DISPLAYбежать crontab, а отсутствие $DBUS_SESSION_BUS_ADDRESSзаставит замедлить отображение изображения.
target_PATH="$PATH:$(sudo printenv PATH)";Полезно использовать прямой путь к корню без необходимости дальнейшего анализа выходных данных envили printenv.
например:
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:~$
Имея другую точку зрения (из FreeBSD), вы получаете:
От 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.
От 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.
Таким образом, эти команды могут иметь тот же эффект без аргументов, но printenvединственная цель состоит в том, чтобы отобразить ключ / значения текущего окружения, в то же время envставя целью установить некоторое окружение перед вызовом другого двоичного файла / сценария / чего угодно.
Разве так понятнее?
Чтобы узнать больше:
man 1 env (FreeBSD)man 1 printenv (FreeBSD)envпоявилась в 4.4BSD. Опции -P, -S и -v были добавлены в FreeBSD 6.0. Команда printenvпоявилась в 3.0BSD. Таким образом, историческая причина, кажется, в том, что printenvпришла первой.
env это POSIX 7 ,printenv это не так (GNU Coreutils в Ubuntu 15.10).
С man-страниц:
env - запустить программу в измененной среде
...
printenv - печатать все или часть окружения
Должно быть довольно объяснительным.
printenvпросто печатает все переменные текущей среды. С envего помощью можно подготовить ту же среду с некоторыми изменениями, если необходимо, и запустить приложение в ней.
lsэто двоичный файл, но llэто общий псевдоним, который обычно просто расширяется до ls -l. printenvи envэто два разных двоичных файла, но я не уверен, какой из них был представлен первым. Вы можете увидеть еще несколько примеров здесь gnu.org/software/coreutils/manual/html_node/env-invocation.html
Говоря строго о функциональности, envэто двоичный файл с огромным набором функций, одна из которых - печать переменных среды, тогда как printenvпросто печатает переменные среды.
Подводя итог, если вы привыкли работать с env, вы будете envпечатать их (потому что это то, к чему вы привыкли), а если нет, вы, как правило, будете помнить printenvбыстрее.
Там практически нет разницы , когда речь идет о printenvпротив envтолько за печать переменных окружения. Я только что проверил, и env немного тяжелее (около 5 лишних КБ), и их производительность (во времени) кажется точно такой же.
Надеюсь, это все прояснит! :)
Если вы действительно хотите знать, как различаются выходные данные двух двоичных файлов, независимо от их истории и наследства, вы можете запустить несколько утилит, чтобы измерить эту разницу. На Debian я запустил несколько вещей, которые будут отличаться в зависимости от любых пользовательских переменных среды:
env |wc -l
printenv |wc -l
Оба моих выхода имеют 41 строку
env > env.txt
printenv > printenv.txt
diff env.txt printenv.txt
Выход: 41c41 <_ = / usr / bin / env ---
_ = / USR / бен / printenv
Итак, вы видите, что есть одна строка, отличающаяся от двух, и эта строка имеет номер 41, который, я думаю, определяет двоичный файл, используемый в команде. Без дополнительных аргументов, они сообщают мне практически идентичную информацию.