phu*_*ehe 45 executable shell-script
有几种方法可以执行脚本。我知道的有:
/path/to/script # using the path (absolute or relative)
. script # using the . (dot)
source script # using the `source` command
Run Code Online (Sandbox Code Playgroud)
有没有其他办法?它们之间有什么区别?在某些情况下,我必须使用一种而不是另一种吗?
Sha*_*off 31
另一种方法是调用解释器并将脚本的路径传递给它:
/bin/sh /path/to/script
Run Code Online (Sandbox Code Playgroud)
点和源是等效的。(编辑:不,它们不是:正如 KeithB 在对另一个答案的评论中指出的那样,“。”仅适用于与 bash 相关的 shell,其中“source”适用于 bash 和 csh 相关的 shell。)它在-place(就像您将脚本复制并粘贴到那里一样)。这意味着脚本中的任何函数和非局部变量都将保留。这也意味着如果脚本将 cd 放入目录,完成后您仍然会在那里。
运行脚本的其他方式将在它自己的子 shell 中运行它。脚本中的变量在完成后不再处于活动状态。如果脚本更改了目录,则不会影响调用环境。
/path/to/script 和 /bin/sh 脚本略有不同。通常,脚本开头有一个“shebang”,如下所示:
#! /bin/bash
Run Code Online (Sandbox Code Playgroud)
这是脚本解释器的路径。如果它指定的解释器与您执行它时的解释器不同,那么它的行为可能会有所不同(或者可能根本不起作用)。
例如,Perl 脚本和 Ruby 脚本以(分别)开头:
#! /bin/perl
Run Code Online (Sandbox Code Playgroud)
和
#! /bin/ruby
Run Code Online (Sandbox Code Playgroud)
如果您通过运行 来执行这些脚本之一/bin/sh script
,那么它们将根本无法工作。
Ubuntu 实际上不使用 bash shell,而是一个非常相似的 shell,称为 dash。需要 bash 的脚本在通过执行调用时可能会稍微出错,/bin/sh script
因为您刚刚使用破折号解释器调用了 bash 脚本。
直接调用脚本和将脚本路径传递给解释器的另一个小区别是,脚本必须标记为可执行才能直接运行,而不是通过将路径传递给解释器来运行。
另一个小变化:您可以使用 eval 为执行脚本的任何这些方式添加前缀,因此,您可以拥有
eval sh script
eval script
eval . script
Run Code Online (Sandbox Code Playgroud)
等等。它实际上并没有改变任何东西,但我想我会把它包括在内是为了彻底。
大多数人通过向脚本添加以下调试标志来调试 shell 脚本:
set -x # Print command traces before executing command.
set -v # Prints shell input lines as they are read.
set -xv # Or do both
Run Code Online (Sandbox Code Playgroud)
但这意味着你需要用编辑器打开文件(假设你有编辑文件的权限),添加一行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
...
...
Run Code Online (Sandbox Code Playgroud)
Shawn J. Goff 提出了很多好观点,但没有包括整个故事:
Ubuntu 实际上不使用 bash shell,而是一个非常相似的 shell,称为 dash。需要 bash 的脚本在通过执行
/bin/sh
脚本调用时可能会稍微出错,因为您刚刚使用破折号解释器调用了 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
Run Code Online (Sandbox Code Playgroud)