执行Bash脚本与采购它有什么区别?


Answers:


344

简短答案

采购脚本将在当前的 shell进程中运行命令。

执行脚本将在新的 Shell进程中运行命令。

如果您希望脚本更改当前正在运行的Shell中的环境,请使用source。否则执行。

如果您仍然感到困惑,请继续阅读。

术语

为了澄清关于执行语法和源语法的一些常见混淆:

./myscript

只要该文件是可执行文件并且位于当前目录中,它将执行 myscript。前导点和斜杠(./)表示当前目录。这是必需的,因为当前目录通常不在中(并且通常不应该在中)$PATH

myscript

如果该文件是可执行文件并且位于中的某个目录中,则将执行 myscript此操作$PATH

source myscript

这将 myscript。该文件不必是可执行文件,但必须是有效的Shell脚本。该文件可以位于当前目录中,也可以位于中的目录中$PATH

. myscript

这也将 myscript。此“拼写”是POSIX定义的官方拼写。Bash定义source为点的别名。

示范

考虑myscript.sh以下内容:

#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD

首先执行脚本之前,请检查当前环境:

$ env | grep FOO
$ echo $PWD
/home/lesmana

该变量FOO未定义,我们位于主目录中。

现在我们执行文件:

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

再次检查环境:

$ env | grep FOO
$ echo $PWD
/home/lesmana

FOO未设置变量,工作目录未更改。

脚本输出清楚地表明已设置了变量并更改了目录。之后的检查表明未设置变量且目录未更改。发生了什么?所做的更改是在新的外壳中进行的。在当前 shell产生一个新的 shell来运行该脚本。该脚本在新的Shell中运行,对环境的所有更改都在新的Shell中生效。脚本完成后,新外壳将销毁。新外壳中对环境的所有更改都将被新外壳破坏。当前外壳中仅打印输出文本。

现在我们文件:

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

再次检查环境:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

设置了变量FOO,并且工作目录已更改。

采购脚本不会创建新的外壳。所有命令都在当前Shell中运行,对环境的更改在当前Shell中生效。

请注意,在这个简单的示例中,执行的输出与采购脚本相同。并非总是如此。

另一个示范

考虑以下脚本pid.sh

#!/bin/sh
echo $$

(特殊变量$$扩展为当前正在运行的shell进程的PID)

首先打印当前shell的PID:

$ echo $$
25009

源脚本:

$ source pid.sh
25009

执行脚本,注意PID:

$ ./pid.sh
25011

再次来源:

$ source pid.sh
25009

再次执行:

$ ./pid.sh
25013

您可以看到,在执行脚本的同时,源代码脚本在同一进程中运行,每次都会创建一个新进程。该新进程是为执行脚本而创建的 shell。输入脚本不会创建新的外壳,因此PID保持不变。

摘要

采购和执行脚本都会在脚本中逐行运行命令,就像您逐行手动键入那些命令一样。

不同之处在于:

  • 当你执行你打开一个脚本壳,在新的shell中键入命令,复制输出回到你当前的shell,然后关闭新壳。对环境的任何更改将仅在新外壳中生效,并且在新外壳关闭后将丢失。
  • 在获取脚本的源代码时,您是在当前 shell 中键入命令。对环境的任何更改将生效并保留在您当前的外壳中。

如果您希望脚本更改当前正在运行的Shell中的环境,请使用source。否则执行。


也可以看看:


2
采购的一种用途是为脚本创建基本形式的配置文件。首先,将各种变量设置为默认值,然后使用诸如myscript.conf之类的源文件-源脚本可以具有覆盖所需值的赋值语句。由于源脚本不是以#/ bin / bash开头,因此不建议直接执行它。
LawrenceC

因此,source有点像在全局范围内运行它,而执行将创建一个新的本地范围。可以将其扩展为脚本中的功能吗?执行一个功能(通常)还是“来源”它?
aliteralmind 2015年

2
是否有使用之间的差异source myscript.sh. myscript.sh
Holloway 2015年

2
如果使用bash,几乎没有区别。source是在bash中加点的别名。
lesmana 2015年

1
当人们提供如此详尽的示例时,即使喜欢我这样的Linux新手,我也喜欢它。谢谢!
Julius

21

执行脚本会在一个单独的子进程中运行它,即,调用一个单独的shell实例来处理脚本。这意味着脚本中定义的任何环境变量等都无法在父(当前)shell中更新。

提供脚本意味着由当前shell本身来解析和执行脚本。就像您键入脚本的内容一样。因此,源脚本不必是可执行的。但是,如果要执行它,它必须是可执行的。

如果您在当前shell中有位置参数,则它们不变。

因此,如果我有一个a.sh包含以下内容的文件:

echo a $*

而且我会:

$ set `date`
$ source ./a.sh

我得到类似的东西:

a Fri Dec 11 07:34:17 PST 2009

鉴于:

$ set `date`
$ ./a.sh

给我:

a

希望能有所帮助。


5
尽管这个答案在各个方面都是正确的,但我很难理解,因为它是使用另一个概念(设置位置参数)进行演示的,在我看来,这比采购和执行自身的差异更加令人困惑。
lesmana

9

采购本质上与一次在命令提示符下键入脚本的每一行相同...

执行将启动一个新过程,然后运行脚本的每一行,仅通过返回的内容修改当前环境。


6

除上述内容外,按./myscript以下顺序执行脚本需要文件myscript的执行权限,而源文件则不需要任何执行权限。这就是为什么chmod +x myscript以前不需要source myscript


2
没错,但是如果有问题,您可以随时运行bash myscript
丹尼尔·贝克

5

采购后,您将获得脚本中定义的所有其他变量。
因此,如果您具有配置或功能定义,则应提供源代码,而不要执行。执行独立于父母环境。


3

如果我没记错的话,执行脚本将在脚本文件所在的#!行中运行可执行文件作为参数(通常使用来启动新的shell并将脚本有效地供应到新的shell中#!/bin/sh);
而采购脚本会在您当前的shell环境中执行每一行,这对更改您的当前shell很有用(例如,提供一种定义shell函数和导出环境变量的方法)。


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.