有几种执行脚本的方法,我知道的是:
/path/to/script # using the path (absolute or relative)
. script # using the . (dot)
source script # using the `source` command
还有更多吗?它们之间有什么区别?在某些情况下,我必须使用一种而不是另一种?
有几种执行脚本的方法,我知道的是:
/path/to/script # using the path (absolute or relative)
. script # using the . (dot)
source script # using the `source` command
还有更多吗?它们之间有什么区别?在某些情况下,我必须使用一种而不是另一种?
Answers:
另一种方法是调用解释器并将脚本的路径传递给它:
/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的shell。需要执行bash的脚本在执行调用时可能会稍微出错,/bin/sh script
因为您刚刚使用破折号解释器调用了bash脚本。
直接调用脚本和将脚本路径传递给解释器之间的另一个小区别是,必须将脚本标记为可执行文件以直接运行它,而不是通过将路径传递给解释器来运行它。
另一个较小的变化:您可以在所有这些方法的前面加上eval来执行脚本,因此,您可以
eval sh script
eval script
eval . script
等等。它实际上并没有改变任何东西,但我想我会为了彻底而将其包括在内。
sh
对应于dash
,但不对应bash
。
大多数人通过向脚本添加以下调试标志来调试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
...
...
emulate sh 2>/dev/null
Shell脚本放在首位。当与zsh一起运行时,这会将其置于POSIX兼容模式。与其他外壳一起运行时,该行无效。然后,我可以使用运行脚本zsh -x /path/to/script
。我在这里喜欢zsh,因为它提供了比bash或ksh更好的跟踪。
肖恩·高夫(Shawn J. Goff)提出了很多要点,但没有包括整个故事:
Ubuntu实际上并不使用bash shell,而是一个非常类似的叫做dash的shell。在执行
/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.sh
,bar/foo.sh
),而不是猜测壳(sh foo.sh
,sh bar/foo.sh
)。shebang应该调用正确的shell。
这是另外两种调用:
cat foo.sh | dash
dash < foo.sh
sh script
bash script
我正在考虑是否还有更多...
.
和source
一样。执行后,script
将保留环境的任何更改。通常,它会被用作Bash库的源代码,因此该库可以在许多不同的脚本中重复使用。
这也是保留当前目录的好方法。如果您在脚本中更改目录,则不会将其应用于执行该脚本的外壳中。但是,如果您找到它来运行它,则在脚本退出后,将保留当前目录。
.
仅适用于sh / bash和相关shell。 source
也可以在csh和相关的shell中使用。
“ userland exec ”算作另一种方式吗?Userland exec无需使用execve()系统调用即可加载代码并使其执行。