it-swarm.cn

执行Shell脚本的不同方法

有几种执行脚本的方法,我知道的是:

/path/to/script # using the path (absolute or relative)
. script        # using the . (dot)
source script   # using the `source` command

还有更多吗?它们之间有什么区别?在某些情况下我必须使用一种而不是另一种吗?

44
phunehehe

另一种方法是调用解释器并将脚本的路径传递给它:

/bin/sh /path/to/script

点和源是等效的。 (编辑:不,不是。正如KeithB在对另一个答案的评论中指出的那样,“。”仅适用于bash相关的shell,而“ source”适用于bash和csh相关的shell。)它在以下位置执行脚本-place(就像您在此处复制并粘贴脚本一样)。这意味着脚本中的所有函数和非局部变量都将保留。这也意味着,如果脚本将cd放入目录中,则完成后您仍会在那里。

运行脚本的其他方式将在其自己的子shell中运行它。完成后,脚本中的变量仍未激活。如果脚本更改了目录,则不会影响调用环境。

/ path/to/script和/ bin/sh脚本略有不同。通常,脚本的开头有一个“ Shebang”,如下所示:

#! /bin/bash

这是脚本解释器的路径。如果它指定的解释器与您执行该解释器时指定的解释器不同,则它的行为可能有所不同(或可能根本无法工作)。

例如,Perl脚本和Ruby脚本分别以()开头:

#! /bin/Perl

#! /bin/Ruby

如果您通过运行/bin/sh script执行这些脚本之一,则它们将根本无法工作。

Ubuntu实际上并不使用bash Shell,而是一种非常相似的叫做dash的工具。进行/bin/sh script调用时,需要bash的脚本可能会稍微出错,因为您刚刚使用破折号解释器调用了bash脚本。

直接调用脚本与将脚本路径传递给解释器之间的另一个小区别是,必须将脚本标记为可执行文件以直接运行它,而不是通过将路径传递给解释器来运行它。

另一个较小的变化:您可以在所有这些方法的前面加上eval来执行脚本,因此,您可以

eval sh script
eval script
eval . script

等等。它实际上并没有改变任何东西,但我想我会为了彻底而将其包括在内。

32
Shawn J. Goff

大多数人通过在脚本中添加以下 调试标志 来调试Shell脚本:

set -x     # Print command traces before executing command.
set -v     # Prints Shell input lines as they are read.
set -xv    # Or do both

但这意味着您需要使用编辑器打开文件(假设您有权编辑文件),并添加set -x,保存文件,然后执行文件。然后,完成后,您需要执行相同的步骤并删除set -x等。这可能很乏味。

您可以在命令行上设置调试标志,而不必执行所有这些操作:

$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total



$ sh -xv ~/bin/ducks  
#!/usr/bin/env bash

# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...
9
Stefan Lasiewski

肖恩·高夫(Shawn J. Goff)提出了很多要点,但没有包括整个故事:

Ubuntu实际上并不使用bash Shell,而是一种非常相似的叫做dash的工具。通过执行/bin/sh脚本进行调用时,需要bash的脚本可能会稍微出错,因为您刚刚使用破折号解释器调用了bash脚本。

许多系统脚本(例如init.d,/ etc等)都有一个Shebang #!/bin/sh,但是/bin/sh实际上是到另一个Shell的符号链接-以前是/bin/bash,现在是/bin/dash。但是,当其中一个被调用为/bin/sh时,它们的行为会有所不同,即它们坚持使用POSIX-compatibility-mode。

他们如何做到这一点?好吧,他们检查了如何调用它们。

Shellscript本身可以测试它的调用方式,并根据此执行不同的操作吗?是的,它可以。因此,您调用它的方式总是会导致不同的结果,但是当然,这样做很少会惹恼您。 :)

根据经验:如果您正在学习bash之类的特定Shell,并从bash教程中编写命令,请在标题中添加#!/bin/bash,而不是#!/bin/sh,除非另有说明。否则您的命令可能会失败。而且,如果您还没有自己编写脚本,请直接调用它(./foo.shbar/foo.sh),而不要猜测Shell(sh foo.shsh bar/foo.sh)。 Shebang应该调用正确的Shell。

这是另外两种调用:

cat foo.sh | dash
dash < foo.sh
7
user unknown

.source等效,因为它们不生成子进程,而是在当前Shell中执行命令。当脚本设置环境变量或更改当前工作目录时,这一点很重要。

使用路径或将其提供给/bin/sh创建一个新的过程,在其中执行命令。

5
mouviciel
sh script
bash script

我正在考虑是否还有更多...

.source相同。执行后,script中的任何环境更改都将保留。通常,它将被用作Bash库的源代码,因此可以在许多不同的脚本中重复使用该库。

这也是保留当前目录的好方法。如果在脚本中更改目录,则该目录将不会在执行该脚本的Shell中应用。但是,如果您找到它来运行它,则在脚本退出后,将保留当前目录。

2
livibetter

。至少在zsh中,源和源有点不同(这就是我使用的),因为

source file

有效,同时

. file

没有,它需要

. ./file
1
bollovan
. ./filename
# ( dot space dot slash filename )

当目录不在路径中时,在当前命令行管理程序中运行脚本。

1
jrh_enginnering

是否将“ serland exec ”计为另一种方式? Userland exec无需使用execve()系统调用就可以加载代码并使其执行。

1
Bruce Ediger