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

WiS*_*GaN 97 environment-variables

这两个命令env和 有printenv什么区别?它们都显示了环境变量,除了_.

有两个命令而不是一个命令有什么历史原因吗?

Fru*_*uit 90

有两个命令而不是一个命令有什么历史原因吗?

有,只是历史的方式。

  1. Bill Joyprintenv于 1979 年为 BSD编写了第一个版本的命令。
  2. UNIX System IIIenv于 1980 年引入了命令。
  3. GNUenv在 1986 年紧随 UNIX 系统之后。
  4. BSDenv于 1988 年紧随 GNU/UNIX 系统。
  5. MINIXprintenv在 1988 年紧随 BSD 之后。
  6. GNUprintenv在 1989 年紧随 MINX/BSD 。
  7. GNU shell编程公用事业1.0包含printenvenv在1991年。
  8. GNU Shell Utilities 于 2002 年合并到 GNU coreutils 中,这就是您现在在 GNU/Linux 中发现的。

请注意,“遵循”并不意味着源代码是相同的,可能它们被重写以避免许可诉讼。

所以,这两个命令存在的原因是因为比尔乔伊printenv甚至在env存在之前写过。经过 10 年的合并/兼容性和 GNU 遇到它,您现在可以在同一页面上看到两个相似的命令。

这段历史记录如下:( 我试图最小化答案,这里只提供了 2 个基本的源代码片段。其余的你可以点击附加的链接查看更多)

[1975年秋天]

同样在 1975 年秋天抵达的还有两个未被注意到的研究生,比尔·乔伊和查克·黑利。他们都对新系统产生了直接的兴趣。最初,他们开始研究一个 Pascal 系统,汤普森在 11/70 机房周围闲逛时将其破解。

[1977]

Joy 开始编译第一个 Berkeley Software Distribution (1BSD),它于 1978 年 3 月 9 日发布。//rf: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution

[1979年2月]

1979(参见“Bill Joy,UCB 二月,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);
}
Run Code Online (Sandbox Code Playgroud)

[1979]

很难确定是在 2BSD 还是 3BSD 中发布的 //rf: https://en.wikipedia.org/wiki/Berkeley_Software_Distribution

[1980年6月]

UNIX 版本 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]$
Run Code Online (Sandbox Code Playgroud)

[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 第一次发布 //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
Run Code Online (Sandbox Code Playgroud)

[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 date dirname env expr groups id logname pathchk printenv printf sleep tee tty whoami yes nice 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 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.
...
Run Code Online (Sandbox Code Playgroud)

[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
Run Code Online (Sandbox Code Playgroud)

[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. 设置变量但毫无意义,因为某些 shell 已经可以不用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.shenv -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:~$
Run Code Online (Sandbox Code Playgroud)

  • 不错的历史课。 (8认同)

Ouk*_*uki 29

有一个不同的观点(来自 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.
Run Code Online (Sandbox Code Playgroud)

来自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.
Run Code Online (Sandbox Code Playgroud)

因此,这些命令在没有参数的情况下可能具有相同的效果,但printenv唯一的目的是显示当前环境键/值,同时env目标是在调用另一个二进制文件/脚本/任何东西之前设置一些环境。

这样更清楚吗?

了解更多:

  • 来自提供的链接: _The `env` 命令出现在 4.4BSD 中。-P, -S 和 -v 选项是在 FreeBSD 6.0._ _The `printenv` 命令出现在 3.0BSD._ 所以历史原因似乎是 `printenv` 先到达。 (2认同)

Cir*_*郝海东 7

env 是 POSIX 7printenv 不是(Ubuntu 15.10 中的 GNU Coreutils)。


UVV*_*UVV 5

来自手册页:

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

...

printenv - 打印全部或部分环境

应该很能解释。

  • 但我不明白... (8认同)

小智 5

严格来说,env它是一个具有大量功能的二进制文件,其中之一是打印环境变量,而printenv只是打印环境变量。

总而言之,如果您习惯使用 env,您将继续env打印它们(因为这就是您习惯的),如果您不习惯,您通常会记住得printenv更快。

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

希望这能解决问题!:)