Shell:如何从另一个shell脚本中调用一个shell脚本?

1136
我有两个 Shell 脚本,a.shb.sh
如何在脚本 a.sh 中调用 b.sh

9
请问您需要的是哪个操作系统以及哪个Shell,还是仅仅是原理上的问题?提供一些示例代码将有助于解决问题。 - jsalonen
19
这不是一个具体的问题,也没有表现出先前解决问题的努力。 - Kris
2
我遇到的一个问题是 b.sh 没有可执行权限。检查一下可能是个好主意。 - seth10
2
在脚本名称前添加 ./,例如,使用 ./b.sh 而不是 b.sh - Benny
2
如果有人一直收到“没有这个文件或目录”错误,请参考以下链接:https://dev59.com/x3E85IYBdhLWcg3wJQCt#2920431 - Amr Lotfy
1
这个解决方案有什么问题吗?:像第一个脚本一样启动第二个脚本。我非常惊讶这个问题能够得到如此高的评分,因为问题中甚至没有呈现最简单的代码或错误信息。 - U. Windl
18个回答

1370

有几种不同的方法可以做到这一点:

  1. 将另一个脚本设为可执行,使用chmod a+x /path/to/file(Nathan Lilienthal的评论),在顶部添加#!/bin/bash行(称为shebang),并将文件所在路径添加到$PATH环境变量中。然后您可以像普通命令一样调用它;

  2. 或者使用source命令调用(它是.的别名),像这样:

    source /path/to/script
    
  3. 或者使用bash命令执行它,例如:

    /bin/bash /path/to/script
    

第一种和第三种方法以另一个进程的方式执行脚本,因此在另一个脚本中的变量和函数将无法访问。
第二种方法在第一个脚本的进程中执行脚本,并从另一个脚本中引入变量和函数(可从调用脚本中使用)。当然,它将运行其他脚本中的所有命令,而不仅仅是设置变量。

在第二种方法中,如果在第二个脚本中使用 exit,它也会退出第一个脚本。这在第一和第三种方法中不会发生。


8
如果Unix环境中上传了由DOS创建的可执行文件,记得使用dos2unix命令更改它们的格式/编码。命令格式为:dos2unix <脚本名称>。 - Abhishek Chatterjee
4
请注意,每个脚本的范围是您项目目录的顶层 - 如果 ./.git/hooks/pre-commit 包含 source foo,则最好确保有 ./foo!(此句话意思是说,如果一个脚本中调用了另一个脚本,在执行时需要确保被调用的脚本存在于指定路径下) - Athan Clark
32
@user528025 中的 . 不是 source 的别名,而是相反的情况。source 是 Bash 的扩展命令,而 . 可以在任何符合 POSIX 标准的 shell 中使用。 - Score_Under
2
在我的情况下,如果被调用的脚本退出,退出脚本是可取的。 - Danijel
1
如果您的两个脚本都在同一个目录中,但仍然不确定您正在调用哪里,那么您将需要通过首先找到脚本目录SCRIPT_DIRECTORY="$(dirname $(realpath "$0"))"来构建脚本路径,然后调用它:source $SCRIPT_DIRECTORY/script.sh - Danijel
显示剩余5条评论

310

看这个。

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."

7
假设 script.sh 与脚本运行的位置在同一个目录下。如果你想要调用其他地方的脚本,你需要输入 sh <脚本路径>/script.sh - Morgan Kenyon
74
这里使用了两个shell,即bashsh。即使sh实际上是bash,它的行为也不同。如果你正在使用#!/bin/bash,那么你可能想要使用bash script.sh(或者只需使用该脚本的散列标记./script.sh)。 - Martin Tournoij
1
即使我将chmod +x设置为.sh文件,仍然不断收到权限被拒绝的错误。有什么建议吗? - isaac weathers
1
@isaacweathers 尝试使用 chmod 777 - Janac Meena
1
@isaacweathers 这表示您的用户未经授权,因此您需要使用sudo,例如 sudo chmod +x - not2savvy
显示剩余2条评论

209

你可以有几种方法来实现这一点。使用终端执行脚本:

#!/bin/bash
SCRIPT_PATH="/path/to/script.sh"

# Here you execute your script
"$SCRIPT_PATH"

# or
. "$SCRIPT_PATH"

# or
source "$SCRIPT_PATH"

# or
bash "$SCRIPT_PATH"

# or
eval '"$SCRIPT_PATH"'

# or
OUTPUT=$("$SCRIPT_PATH")
echo $OUTPUT

# or
OUTPUT=`"$SCRIPT_PATH"`
echo $OUTPUT

# or
("$SCRIPT_PATH")

# or
(exec "$SCRIPT_PATH")

所有这些对于带有空格的路径都是正确的!!!


76
它们有何不同?为什么选一个而不选另一个? - rocketspacer
"$SCRIPT_PATH" 是首选。 - Harry Mumford-Turner
1
我可以补充一下,这些并不全等。例如,sh "$SCRIPT_PATH" 和 bash "$SCRIPT_PATH" 将无法运行 #!/usr/bin/expect 脚本,而仅使用 "$SCRIPT_PATH" 则可以。 - Tahlor
如果你需要将参数传递到第二个脚本中,我认为"$SCRIPT_PATH"source.都不起作用。但是.//bin/bash或更短的bash都可以使用。 - postal
请注意,1-3需要脚本可执行,而例如4则不需要。我认为这应该包含/编辑在答案中,对吗? - sb813322
source. 的同义词,参考 https://unix.stackexchange.com/a/459089/21027。 - maksimov

69

我正在寻找的答案:

( exec "path/to/script" )

如上所述,exec 代替了Shell而不会创建新的进程。但是,我们可以将其放在子Shell中,使用括号实现。

编辑: 实际上 ( "path/to/script" ) 就足够了。


14
这似乎有些复杂。为什么不直接使用“/path/to/script”调用它呢?我完全看不出这里需要使用“exec”吗? - Martin Tournoij
不需要子shell,因为你没有执行exec - Karel Vlk
9
你如何使用参数执行这个脚本? - Bhargav
如果你想继续捕获子脚本的输出,请尝试$(source "path/to/script")。 - cmcginty
@Bhargav 请访问以下链接 https://dev59.com/3mYq5IYBdhLWcg3wpyRE - Mustafa Demir

39

如果您在同一个目录中有另一个文件,则可以执行以下操作:

bash another_script.sh
或者
source another_script.sh
. another_script.sh
当您使用bash而不是source时,脚本无法更改父脚本的环境变量。 . 命令是POSIX标准,而source命令是对.的更易读的bash同义词(我更喜欢source而不是.)。 如果您的脚本位于其他位置,请提供该脚本的路径。 相对路径和完整路径都应该可以工作。

22

取决于。 简而言之... 如果你想在当前控制台加载变量并执行,可以在你的代码中使用source myshellfile.sh。例如:

取决于。 简要地说... 如果您想要将变量加载到当前控制台并执行,则可以在您的代码中使用source myshellfile.sh。示例:

#!/bin/bash
set -x
echo "This is an example of run another INTO this session."
source my_lib_of_variables_and_functions.sh
echo "The function internal_function() is defined into my lib."
returned_value=internal_function()
echo $this_is_an_internal_variable

set +x

如果你只想执行一个文件,对你来说唯一感兴趣的是结果,你可以这样做:

#!/bin/bash
set -x
./executing_only.sh
bash i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x

3
请注意,source 是 Bash 特有的功能。标准 Bourne Shell 只有 . (例如 . other_script.sh)。 - Martin Tournoij
关于shbash之间的区别,您可以考虑一些这个U&L问题的答案。例如,在使用read命令时,两者之间存在很大的差异。 - Cadoiz

16

您可以使用/bin/sh调用或执行另一个脚本(通过您的实际脚本):

 # cat showdate.sh
 #!/bin/bash
 echo "Date is: `date`"

 # cat mainscript.sh
 #!/bin/bash
 echo "You are login as: `whoami`"
 echo "`/bin/sh ./showdate.sh`" # exact path for the script file
输出将是:
 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013

3
这肯定会在/bin/sh下运行showdate.sh,而不是/bin/bash下运行? - Chris Watts
我已经尝试过 "/bin/sh ./showdate.sh"、"/bin/bash ./showdate.sh" 和 "./showdate.sh",并运行了文件:mainscript.sh,得到了相同的输出。 - Ranjithkumar T
1
关于shbash之间的区别,您可以考虑一些这个U&L问题的答案。例如,在使用read命令时,两者之间存在很大的差异。 - sb813322

13

首先,您必须包含所调用的文件:

#!/bin/bash
. includes/included_file.sh

那么您可以这样调用您的函数:
#!/bin/bash
my_called_function

12

简单的源代码能够帮助您。

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"

11

只需在一行中添加您将要在终端中键入以执行脚本的内容!
例如:

#!bin/bash
./myscript.sh &

如果要执行的脚本不在同一目录下,只需使用脚本的完整路径。
例如:`/home/user/script-directory/./myscript.sh &


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接