毕竟,bash中的“。”和“source”之间有区别吗?

我一直在寻找“。”之间的区别。 和“源”内置命令和一些来源(例如,在本讨论和bash手册页中)表明这些是相同的。

但是,在环境变量出现问题后,我进行了测试。 我创建了一个文件testenv.sh ,其中包含:

 #!/bin/bash echo $MY_VAR 

在命令提示符中,我执行了以下操作:

 > chmod +x testenv.sh > MY_VAR=12345 > ./testenv.sh > source testenv.sh 12345 > MY_VAR=12345 ./testenv.sh 12345 

[注意第一个表单返回一个空字符串]

所以,这个小小的实验表明毕竟存在差异,对于“source”命令,子环境inheritance了父级的所有变量,其中“。”。 它不是。

我错过了什么,或者这是bash的未记录/弃用function?

[GNU bash,版本4.1.5(1)-release(x86_64-pc-linux-gnu)]

简答

在你的问题中,第二个命令既不使用. shell内置也没有内置的source 。 相反,您实际上是通过按名称调用(就像任何其他可执行文件一样)在单独的shell中运行脚本。 这确实为它提供了一组单独的环境变量(尽管如果在其父shell中导出环境变量,它将被包含在内)。 如果你将/更改为一个空格,那么它将使用. 内置,相当于source

扩展说明

这是内置source shell的语法,它执行当前shell中脚本的内容(因此使用当前shell的环境变量):

 source testenv.sh 

这是语法. 内置的,它做的与source相同:

 . testenv.sh 

但是,此语法将脚本作为可执行文件运行,启动新shell以运行它:

 ./testenv.sh 

那不是用的. 内置。 相反, . 是您正在执行的文件的路径的一部分。 一般来说,您可以通过使用包含至少一个/字符的名称调用shell来运行任何可执行文件。 要在当前目录中运行文件,在./是最简单的方法。 除非当前目录位于PATH ,否则无法使用命令testenv.sh运行该脚本。 这是为了防止人们在打算执行系统命令或PATH环境变量中列出的某个目录中存在的某些其他文件时意外执行当前目录中的文件。

由于按名称运行文件(而不是使用source. )在新shell中运行它,因此它将拥有自己的一组环境变量。 环境变量inheritance自调用进程的环境变量(在本例中是您的交互式shell)。 但是,对于要传递给新shell的环境变量,必须满足以下条件之一:

  • 环境变量已导出。 使用内置的export shell进行此操作。 在您的示例中,您可以使用export MY_VAR=12345一步设置和导出变量,或者如果已经设置,您只需使用export MY_VAR

  • 为您正在运行的命令显式设置并传递环境变量。 这通常可以实现:

     MY_VAR=12345 ./testenv.sh 

./脚本语法需要Hashbang线才能正常工作(正确)

顺便提一下,请注意,当你按照上面的名称调用可执行文件时(而不是使用.source shell内置函数),使用什么shell程序来运行它通常不是由你正在运行的shell决定的来自。 代替:

  • 对于二进制文件,可以将内核配置为运行该特定类型的文件。 它检查文件的前两个字节是否有“幻数” ,表示它是什么类型的二进制可执行文件。 这是可执行二进制文件能够运行的方式。

    当然,这非常重要,因为脚本无法在没有shell或其他解释器的情况下运行,这是一个可执行的二进制文件! 此外,许多命令和应用程序都是编译的二进制文件而不是脚本。

    #!是表示文本可执行文件的“幻数”的文本表示。)

  • 对于应该以shell或其他解释语言运行的文件,第一行如下所示:

     #!/bin/sh 

    /bin/sh可以替换为任何其他shell或解释器用于运行程序。 例如,Python程序可能从该行开始:

     #!/usr/bin/python 

    这些行称为hashbang,shebang和许多其他类似名称。 请参阅此FOLDOC条目 ,这篇维基百科文章和解释器读取的#!/ bin / sh? 欲获得更多信息。

  • 如果文本文件被标记为可执行文件并且您从shell运行它(例如./filename ),但它不#!开头#! ,内核无法执行它。 但是,看到发生这种情况,您的shell将尝试通过将其名称传递给某个 shell来运行它。 对shell的要求很少 ( “shell应该执行一个等同于调用shell的命令……” )。 在实践中 ,一些shell–包括bash * – 运行自己的另一个实例,而其他shell使用/bin/sh 。 我强烈建议你避免这种情况并改为使用hashbang行(或者通过将脚本传递给所需的解释器来运行脚本,例如bash filename )。

    * GNU Bash手册 , 3.7.2命令搜索和执行 :“如果由于文件不是可执行格式而导致此执行失败,并且该文件不是目录,则假定它是一个shell脚本 ,并且shell按照描述执行它在Shell Scripts中 。“

是的,你错过了什么。

我觉得你混淆了’。’ 这意味着当前目录,如./testenv.sh和’。’ 这意味着source (这是一个内置命令)。 所以在’。’的情况下 它意味着source . ./testenv.sh . ./testenv.sh 。 合理?

所以试试这个:

 MY_VAR=12345 . ./testenv.sh