“ env”和“ printenv”有什么区别?


67

这两个命令env和之间有什么区别printenv?它们都显示了环境变量,除了,输出也完全相同_

历史上是否有两个命令而不是一个命令的原因?

Answers:


49

历史上是否有两个命令而不是一个命令的原因?

只是历史的举止。

  1. Bill Joy printenv在1979年为BSD 编写了第一版Command。
  2. UNIX System III env在1980年引入了命令。
  3. GNU env在1986年跟随UNIX System 。
  4. BSD env在1988年遵循GNU / UNIX系统。
  5. MINIX printenv在1988年跟随BSD 。
  6. GNU printenv在1989年跟随MINX / BSD 。
  7. GNU shell编程公用事业1.0包含printenvenv在1991年。
  8. GNU Shell实用程序在2002年合并到GNU coreutils中,这在当今的GNU / Linux中很容易找到。

请注意,“跟随”并不意味着源代码相同,可能是为了避免许可诉讼而对其进行了重写。

因此,两个命令都存在的原因是,当Bill Joy编写printenv该时间时,env尚不存在。经过10年的合并/兼容性和GNU,您现在在同一页面上看到两个相似的命令。

此历史记录表示如下:( 我尝试将答案最小化,因此此处仅提供2个基本源代码,其余的您可以单击附件链接查看)

[1975年秋天]

也是在1975年秋天到达的还有两名未被注意的研究生Bill Joy和Chuck Haley;他们俩都立即对新系统产生了兴趣。最初,他们开始研究汤普森在11/70机房周围闲逛时遭到黑客入侵的Pascal系统。

[1977]

Joy于1978年3月9日开始发行第一个Berkeley软件发行版(1BSD)。// rf:https ://en.wikipedia.org/wiki/Berkeley_Software_Distribution

[1979年2月]

1979(请参阅“ Bill Joy,UCB,1979年2月”)/ 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中发布// //射频:https://en.wikipedia.org/wiki/Berkeley_Software_Distribution

[1980年6月]

UNIX版本3.0或“ UNIX系统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首先printenv手册// rf:http ://minnie.tuhs.org/cgi-bin/utree.pl?file=2.11BSD/src/man/man1/printenv.1 但我找不到与env相关的手册,最接近的是getenv和environ // // 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 1st发布// rf:https : //en.wikipedia.org/wiki/Andrew_S._Tanenbaum

  • Tanenbaum为IBM PC编写了UNIX的克隆版本,称为MINIX(MINi-unIX)。它针对的是希望学习操作系统如何工作的学生和其他人。

[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

[1988年10月4日]

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,请参阅[1993年8月12日]。

[1991年7月16日]

“Shellutils” -发布GNU shell编程公用事业1.0 // RF:https://groups.google.com/forum/#!topic/gnu.announce/xpTRtuFpNQc

该软件包中的程序是:

basename日期dirname env expr组id日志名pathchk printenv printf sleep tee tty whoami是不错nohup stty uname

[1993年8月12日]

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

,GNU Shell实用程序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]

在2006年在DSLinux源代码上找到的printenv.c // 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

[1993年11月]

FreeBSD的第一个版本已经发布。// RF:https://en.wikipedia.org/wiki/FreeBSD

[2002年9月1日]

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

GNU fileutils,textutils和sh-utils(参见1991年7月16日的“ Shellutils”)软件包已合并为一个软件包,称为GNU coreutils。

总体而言,env用例与printenv

  1. 打印环境变量,但是printenv可以做同样的事情
  2. 禁用内置的shell,但也可以使用enablecmd 实现。
  3. 设置变量但没有意义,因为有些外壳已经可以做到了env,例如

    $ HOME = / dev HOME = / tmp USER = root / bin / bash -c“ cd〜; pwd”

    / tmp

  4. #!/usr/bin/env python标头,但如果env不在/ usr / bin中,则仍不可移植

  5. env -i,禁用所有环境。我发现找出某些程序的关键环境变量以使其从运行很有用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则会减慢图像的显示速度。

  6. target_PATH="$PATH:$(sudo printenv PATH)";直接使用根路径而无需进一步解析envor 的输出很有用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:~$

4
美好的历史课。
Ouki,2016年

21

从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目标是在调用另一个二进制文件/脚本/任何东西之前设置环境。

这样更清楚吗?

要知道更多:


2
通过提供的链接:env命令出现在4.4BSD中。在FreeBSD 6.0中增加了-P,-S和-v选项。 printenv命令出现在3.0BSD中。因此,历史原因似乎是printenv首先到达的。
mcmlxxxvi 2015年


3

从手册页:

env-在修改后的环境中运行程序

...

printenv-打印全部或部分环境

应该很好解释。


4
但我不明白……
mikeserv 2014年

我想env在printenv之前。那为什么还要制作另一个二进制文件呢?这与“ ll”到“ ls”的含义不同,因为“ ll”不是二进制文件并且没有手册页。
WiSaGaN 2014年

@mikeserv printenv只是打印当前环境的所有变量。有了env你可以准备与必要时一些修改同一个环境中,并在其中运行的应用程序。
UVV 2014年

@WiSaGaN您的比较并不正确。ls是二进制文件,但是ll常用别名,通常会扩展为ls -lprintenv并且env是两种不同的二进制文件,但我不确定首先介绍哪种二进制文件。你可以在这里看到更多的例子gnu.org/software/coreutils/manual/html_node/env-invocation.html
UVV

1
@mikeserv,请参阅此漫画上的鼠标悬停文本。:)
通配符

3

严格地讲功能,env是具有大量功能的二进制文件,其中之一是打印环境变量,而printenv仅打印环境变量。

总结一下,如果您习惯使用env,则将使用env它们进行打印(因为这是您惯用的方法),如果您不习惯,则通常会记得printenv更快。

printenvenv仅打印环境变量相比,谈论实际上几乎没有区别。我刚刚检查了一下,env稍重(大约多了5 KB),并且它们的性能(及时)似乎完全相同。

希望这可以解决!:)


-1

如果您真的想知道这两个二进制文件的历史记录和历史记录如何,那么它们的输出有何不同,可以运行一些实用程序来评估这种差异。在debian上,我运行了一些内容,具体取决于任何自定义环境var:

env |wc -l
printenv |wc -l

我的输出都有41行

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

输出:41c41 <_ = / usr / bin / env-

_ = / usr / bin / printenv

因此,您会看到两者之间有一行不同,而那一行是数字41,我想这是命令中使用的二进制代码。在没有其他参数的情况下,这些为我报告了虚拟的相同信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.