执行 shell 脚本的不同方式

执行 shell 脚本的不同方式

有多种方法可以执行脚本。我所知道的有:

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

还有其他办法吗?它们之间有什么区别?是否存在我必须使用其中一种而不是另一种的情况?

答案1

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

/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,而是使用一种非常相似的 shell,称为 dash。当通过 do 调用时,需要 bash 的脚本可能会稍微出错,/bin/sh script因为您刚刚使用破折号解释器调用了 bash 脚本。

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

另一个小变化:您可以使用 eval 作为执行脚本的任何方法的前缀,因此,您可以

eval sh script
eval script
eval . script

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

答案2

大多数人通过添加以下内容来调试 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
...
...

答案3

Shawn J. Goff 提出了很多好的观点,但没有包含整个故事:

Ubuntu 实际上不使用 bash shell,而是使用一个非常相似的名为 dash 的 shell。需要 bash 的脚本在通过/bin/shscript 调用时可能会出现轻微错误,因为您刚刚使用 dash 解释器调用了一个 bash 脚本。

许多系统脚本(例如在 init.d 中、在 /etc 中等)都有一个 shebang #!/bin/sh,但/bin/sh实际上是到另一个 shell 的符号链接 - 无论是过去/bin/bash还是现在/bin/dash。但是当其中之一被调用为 时/bin/sh,它们的行为有所不同,即它们坚持 POSIX 兼容模式。

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

shellscript 本身可以测试它是如何被调用的,并根据情况做不同的事情吗?是的,它可以。所以你调用它的方式总是会导致不同的结果,但当然很少这样做会惹恼你。 :)

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

这里还有另外两种调用:

cat foo.sh | dash
dash < foo.sh

答案4

sh script
bash script

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

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

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

相关内容