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

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

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

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

答案1

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

这就是历史的方式。

历史

  1. printenvBill Joy于 1979 年为 BSD编写了命令的第一个版本。
  2. UNIX System IIIenv于 1980 年引入了命令。
  3. GNU 于 1986 年继 UNIX 系统之后出现env
  4. BSD 于 1988 年继 GNU/UNIX 系统之后出现env
  5. MINIX 于 1988 年紧随 BSD 的脚步printenv
  6. GNU 于 1989 年跟随 MINX/BSD 的脚步printenv
  7. 1991 年printenv包含GNU shell 编程实用程序 1.0 。env
  8. GNU Shell Utilities 于 2002 年合并到 GNU coreutils,这就是您现在在 GNU/Linux 中看到的。

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

因此,这两个命令之所以存在,是因为 Bill Joy在存在printenv之前就已经写过env。经过 10 年的合并/兼容性和 GNU 遇到它之后,您现在可以在同一页面上看到两个相似的命令。

这段历史表明: (我试图尽量减少答案,只在这里提供了两个基本的源代码片段。其余的你可以点击附加的链接查看更多)

[1975年秋天]

1975 年秋天,还有两名未被注意到的研究生比尔·乔伊 (Bill Joy) 和查克·黑利 (Chuck Haley) 也来到了这里。他们都立即对新系统产生了兴趣。最初,他们开始研究汤普森在 11/70 机房闲逛时一起破解的 Pascal 系统。

[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?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]

很难确定是在 2BSD 还是 3BSD 中发布的 //rf: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 已经存在

//射频: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

该软件包中的程序有:

基本名称 日期 目录名环境expr 组 id 日志名 路径chk打印环境 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]

printenv.c 于 2006 年在 DSLinux 源代码中找到 //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 的第一个版本发布。 //射频: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 内置功能,但enable也可以使用 cmd 实现。

  3. 设置变量但毫无意义,因为某些 shell 已经可以在没有 的情况下完成它env,例如

        $ HOME=/dev HOME=/tmp USER=root /bin/bash -c "cd ~; pwd"
    
            /tmp
    
    
  4. #!/usr/bin/env pythonenv标头,但如果不在 /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:~$
    

答案2

拥有不同的观点(来自 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目标是在调用另一个二进制文件/脚本/任何内容之前设置一些环境。

这样是不是更清楚了?

想了解更多:

答案3

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

答案4

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

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

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

希望这能解决问题! :)

相关内容