【问题标题】:Shell: How to call one shell script from another shell script?Shell:如何从另一个 shell 脚本调用一个 shell 脚本?
【发布时间】:2012-01-11 06:39:08
【问题描述】:

我有两个 shell 脚本,a.shb.sh

如何从 shell 脚本 a.sh 中调用 b.sh

【问题讨论】:

  • 您能否提供一些细节:哪个操作系统和哪个外壳,或者您只是在原则上谈论这个问题?示例代码也会有所帮助。
  • 这不是一个真正的具体问题,也没有表明解决该问题的先前努力。
  • 我遇到的一个问题是b.sh 没有可执行权限。检查一下可能是件好事。
  • 在脚本名称前追加./,例如:b.sh,使用:./b.sh
  • 如果有人不断收到No such file or directory 错误*.com/a/2920431/1356559

标签: bash shell


【解决方案1】:

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

  1. 使其他脚本可执行,在顶部添加#!/bin/bash 行,并将文件所在的路径添加到$PATH 环境变量。然后你就可以把它当成一个普通的命令来调用了;

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

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

    /bin/bash /path/to/script
    

第一种和第三种方法将脚本作为另一个进程执行,因此另一个脚本中的变量和函数将无法访问。
第二种方法在第一个脚本的进程中执行脚本,并拉入变量和其他脚本中的函数(因此它们可以从调用脚本中使用)。

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

【讨论】:

  • 记得chmod a+x /path/to/file 否则它将无法执行。仅适用于 ./script 方法。
  • 如果在 DOS 下创建后上传到 unix 环境,记得更改 unix 中可执行文件的格式/编码 -> dos2unix
  • 另外,注意每个脚本的作用域是你项目目录的顶层——如果./.git/hooks/pre-commitsource foo,你最好有./foo
  • source 的问题是被调用脚本中的exit 语句也会退出你的...
  • @user528025 . 不是source 的别名,而是相反。 source 是一个 bash 扩展,而 . 可以在任何 POSIX 兼容的 shell 中工作。
【解决方案2】:

看看这个。

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

【讨论】:

  • 这假定 script.sh 与正在运行的任何脚本位于同一目录中。如果你想在其他地方调用脚本,你会说sh <path to script>/script.sh
  • 这也使用了 两个 shell,bashsh。即使sh 实际上是bash,它的行为也不相同。如果您使用的是#!/bin/bash,那么您可能想使用bash script.sh(或者只是./script.sh 来使用该脚本的hashbang)。
  • 即使我将 chmod +x 设置为 .sh 文件,仍会出现权限被拒绝错误。有什么建议吗?
  • @isaacweathers 尝试 chmod 777
  • @isaacweathers 这表示你的用户没有被授权,所以你需要像sudo chmod +x那样使用sudo
【解决方案3】:

有几种方法可以做到这一点。终端执行脚本:

#!/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")

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

【讨论】:

  • 它们有什么区别?为什么一个,为什么另一个?
  • 。首选“$SCRIPT_PATH”
  • 我可以补充一点,这些并不都是等价的,例如sh "$SCRIPT_PATH" 和 bash "$SCRIPT_PATH" 不会运行 #!/usr/bin/expect 脚本,而只有 "$SCRIPT_PATH" 会。
  • 如果您需要将参数传递到第二个脚本中,"$SCRIPT_PATH"source. 不工作,我可以看到。 .//bin/bash 或更短的 bash 都可以工作。
【解决方案4】:

我一直在寻找的答案:

( exec "path/to/script" )

如前所述,exec 在不创建新进程的情况下替换了 shell。 然而,我们可以把它放在一个子shell中,这是使用括号完成的。

编辑: 其实( "path/to/script" )就够了。

【讨论】:

  • 这看起来很复杂。为什么不直接用/path/to/script 调用它?我认为这里根本不需要exec
  • 也不需要子shell,因为您不是execing。
  • 你将如何使用参数执行这个脚本?
  • 如果您仍想捕获子脚本的输出,请尝试 $(source "path/to/script")
  • @Bhargav 关注此链接*.com/questions/14302389/…
【解决方案5】:

如果您在同一目录中有另一个文件,您可以这样做:

bash another_script.sh

source another_script.sh

. another_script.sh

当您使用bash 而不是source 时,脚本无法改变父脚本的环境。 . 命令是 POSIX 标准,而 source 命令是 . 的更易读的 bash 同义词(我更喜欢 source 而不是 .)。如果您的脚本位于其他地方,只需提供该脚本的路径。相对路径和完整路径都应该有效。

【讨论】:

    【解决方案6】:

    取决于。 简要地... 如果您想在当前控制台上加载变量并执行,您可以在代码上使用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
    sh i_can_execute_this_way_too.sh
    bash or_this_way.sh
    set +x
    

    希望对你有帮助。 谢谢。

    【讨论】:

    • 请注意,source 是特定于 bash 的功能。标准的 bourne shell 只有.(例如. other_script.sh)。
    【解决方案7】:

    您可以使用/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
    

    【讨论】:

    • 这肯定会在 /bin/sh 而不是 /bin/bash 下运行 showdate.sh
    • 我尝试过使用“/bin/sh ./showdate.sh”、“/bin/bash ./showdate.sh”、“./showdate.sh”并运行文件:mainscript.sh 并得到相同的输出。
    【解决方案8】:

    简单的来源会帮助你。 例如。

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

    【讨论】:

      【解决方案9】:

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

      #!bin/bash
      ./myscript.sh &
      

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

      【讨论】:

        【解决方案10】:

        首先你必须包含你调用的文件:

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

        然后你这样调用你的函数:

        #!/bin/bash
        my_called_function
        

        【讨论】:

          【解决方案11】:

          这对我有用,这是执行另一个主 sh 脚本的内容。

          #!/bin/bash 
          source /path/to/other.sh
          

          【讨论】:

            【解决方案12】:

            最佳答案建议将#!/bin/bash 行添加到被调用的子脚本的第一行。但是即使添加了 shebang,在子 shell 中运行脚本并捕获输出也会快得多*

            $(source SCRIPT_NAME)

            当您想要继续运行相同的解释器(例如,从 bash 到另一个 bash 脚本)并确保不执行子脚本的 shebang 行时,此方法有效。

            例如:

            #!/bin/bash
            SUB_SCRIPT=$(mktemp)
            echo "#!/bin/bash" > $SUB_SCRIPT
            echo 'echo $1' >> $SUB_SCRIPT
            chmod +x $SUB_SCRIPT
            if [[ $1 == "--source" ]]; then
              for X in $(seq 100); do
                MODE=$(source $SUB_SCRIPT "source on")
              done
            else
              for X in $(seq 100); do
                MODE=$($SUB_SCRIPT "source off")
              done
            fi
            echo $MODE
            rm $SUB_SCRIPT
            

            输出:

            ~ ❯❯❯ time ./test.sh
            source off
            ./test.sh  0.15s user 0.16s system 87% cpu 0.360 total
            
            ~ ❯❯❯ time ./test.sh --source
            source on
            ./test.sh --source  0.05s user 0.06s system 95% cpu 0.114 total
            

            * 例如,当病毒或安全工具在设备上运行时,执行新进程可能需要额外的 100 毫秒。

            【讨论】:

              【解决方案13】:
              pathToShell="/home/praveen/"   
              chmod a+x $pathToShell"myShell.sh"
              sh $pathToShell"myShell.sh"
              

              【讨论】:

                【解决方案14】:
                 #!/bin/bash
                
                 # Here you define the absolute path of your script
                
                 scriptPath="/home/user/pathScript/"
                
                 # Name of your script
                
                 scriptName="myscript.sh"
                
                 # Here you execute your script
                
                 $scriptPath/$scriptName
                
                 # Result of script execution
                
                 result=$?
                

                【讨论】:

                • 文件夹scriptPath 或文件名scriptName 不正确
                【解决方案15】:
                chmod a+x /path/to/file-to-be-executed
                

                这是我唯一需要的。一旦要执行的脚本像这样可执行,您(至少在我的情况下)在调用脚本时不需要任何其他额外操作,例如 sh./

                感谢@Nathan Lilienthal 的评论

                【讨论】:

                  【解决方案16】:

                  假设新文件为“/home/satya/app/app_specific_env”,文件内容如下

                  #!bin/bash
                  
                  export FAV_NUMBER="2211"
                  

                  将此文件引用附加到 ~/.bashrc 文件

                  source /home/satya/app/app_specific_env
                  

                  当您重新启动机器或重新登录时,请在终端中尝试echo $FAV_NUMBER。它将输出该值。

                  如果你想马上看到效果,在命令行中source ~/.bashrc

                  【讨论】:

                    【解决方案17】:

                    从其他文件导入函数有一些问题。
                    首先:你不需要做这个文件可执行。最好不要这样做! 只需添加

                    . file
                    

                    导入所有功能。并且所有这些都将如同在您的文件中定义一样。
                    第二:您可以定义具有相同名称的函数。它将被覆盖。这不好。你可以这样声明

                    declare -f new_function_name=old_function_name 
                    

                    只有在那之后才进行导入。 因此,您可以用新名称调用旧函数。
                    第三:您可以只导入文件中定义的函数的完整列表。 如果有些不需要,您可以取消设置它们。但是如果你在 unset 之后重写你的函数,它们就会丢失。但是如果你按照上面的描述设置了对它的引用,你可以在 unset 后用相同的名字恢复。
                    最后 通常导入的过​​程是危险的,不是那么简单。当心!您可以编写脚本来更轻松、更安全地执行此操作。 如果您只使用部分功能(不是全部),最好将它们拆分到不同的文件中。不幸的是,这种技术在 bash 中做得不好。例如,在 python 和其他一些脚本语言中,它既简单又安全。可以仅使用自己的名称进行部分导入所需的功能。我们都希望在下一个布什版本中能够完成相同的功能。但是现在我们必须编写许多额外的代码才能做你想做的事。

                    【讨论】:

                    • (欢迎来到 SO!)由于用户 Praveen 最后一次出现是在 2011 年,因此很难弄清楚问题是否是如何使 shell 执行 a.sh 执行 b.sh (并继续执行 a.sh 如果没有其他命令),或按字面意思调用b .sh。 (我的拼写检查器没有捕捉到bush versions。)(你有没有人可以帮助你学习英语语法?(有时希望我有。))
                    【解决方案18】:

                    使用反引号。

                    $ ./script-that-consumes-argument.sh `sh script-that-produces-argument.sh`
                    

                    然后获取生产者脚本的输出作为消费者脚本的参数。

                    【讨论】:

                      相关资源