【问题标题】:Can I call a function of a shell script from another shell script?我可以从另一个 shell 脚本调用一个 shell 脚本的函数吗?
【发布时间】:2012-06-05 01:43:57
【问题描述】:

我有 2 个 shell 脚本。

第二个shell脚本包含以下函数 second.sh

func1 
func2

first.sh 将调用带有一些参数的第二个 shell 脚本和 将使用特定于该函数的一些其他参数调用 func1 和 func2。

这是我所说的例子

second.sh

val1=`echo $1`
val2=`echo $2`

function func1 {

fun=`echo $1`
book=`echo $2`

}

function func2 {

fun2=`echo $1`
book2=`echo $2`


}

first.sh

second.sh cricket football

func1 love horror
func2 ball mystery

我怎样才能实现它?

【问题讨论】:

  • v=$(echo $1) 完全是多余的。只需写fun2=$1。唯一的区别是$()(或反引号)将删除尾随的换行符。
  • 由于从 shell 脚本调用函数与命令行相比没有什么特别之处,所以这个问题可以简化为“如何调用 bash 函数?”

标签: shell unix


【解决方案1】:

像这样重构你的 second.sh 脚本:

func1 {
   fun="$1"
   book="$2"
   printf "func=%s,book=%s\n" "$fun" "$book"
}

func2 {
   fun2="$1"
   book2="$2"
   printf "func2=%s,book2=%s\n" "$fun2" "$book2"
}

然后像这样从脚本first.sh 调用这些函数:

source ./second.sh
func1 love horror
func2 ball mystery

输出:

func=love,book=horror
func2=ball,book2=mystery

【讨论】:

  • 为避免意外的副作用,请注意source 命令实际上会运行作为参数传递的脚本。
  • @dvlcube 如果你能提出一个替代方案会更好。
  • 这个答案很清楚很好。重要的是,*.com/a/42101141/852196 描述了一些人可能遇到的问题,并提供了一个优雅的通用解决方案。
  • @Alpha2k 我不确定是否有替代方案。这个想法是“小心你在源文件中放入的内容”
【解决方案2】:

您不能直接调用另一个 shell 脚本中的函数。

您可以将您的函数定义移动到一个单独的文件中,然后使用. 命令将它们加载到您的脚本中,如下所示:

. /path/to/functions.sh

这会将functions.sh 解释为好像它的内容此时实际存在于您的文件中。这是实现 shell 函数共享库的常用机制。

【讨论】:

  • 这与接受的答案不一样吗,因为.source 的别名?
  • 好吧,我先回答了,所以从技术上讲,接受的答案与这个相同:)。此外,虽然source 在许多shell 中是. 的别名,但情况并非总是如此。例如,Debian 上提供/bin/shdash 软件包没有source 命令。
  • source 命令在 Ubuntu @ajsharma 中不起作用。参考:source command not found in sh shell
  • 太奇怪了,这条评论没有被评为最高?这是正确的 #!/bin/sh 语法,另一种只能在 bash 中使用。
【解决方案3】:

问题

当前接受的答案仅在重要条件下有效。给定...

/foo/bar/first.sh:

function func1 {  
   echo "Hello $1"
}

/foo/bar/second.sh:

#!/bin/bash

source ./first.sh
func1 World

这只有在first.sh 是从first.sh 所在的同一目录中执行时才有效。 IE。如果shell当前工作路径为/foo,则尝试运行命令

cd /foo
./bar/second.sh

打印错误:

/foo/bar/second.sh: line 4: func1: command not found

这是因为source ./first.sh 是相对于当前工作路径的,而不是脚本的路径。因此,一种解决方案可能是利用 subshel​​l 并运行

(cd /foo/bar; ./second.sh)

更通用的解决方案

鉴于...

/foo/bar/first.sh:

function func1 {  
   echo "Hello $1"
}

/foo/bar/second.sh:

#!/bin/bash

source $(dirname "$0")/first.sh

func1 World

然后

cd /foo
./bar/second.sh

打印

Hello World

工作原理

  • $0 返回执行脚本的相对或绝对路径
  • dirname 返回目录的相对路径,$0 脚本所在的目录
  • $( dirname "$0" ) dirname "$0" 命令返回相对 执行脚本的目录路径,然后用作source 命令的参数
  • 在“second.sh”中,/first.sh只是附加了导入的shell脚本的名称
  • source 将指定文件的内容加载到当前 贝壳

【讨论】:

  • 这正是我所需要的。非常感谢!
【解决方案4】:

second.sh

#!/bin/bash

function func1() {
   fun="$1"
   book="$2"
   echo "$fun, $book\n"
}

function func2() {
   fun2="$1"
   book2="$2"
   printf "$fun2, $book2\n"
}

first.sh

#!/bin/bash

source /absolute_path_to/second.sh
func1 love horror
func2 ball mystery

在使用之前你需要记住这些事情

  • 关键字source.(句点)是同一个命令。
  • 如果FILENAME 不是文件的完整路径,该命令将在$PATH 环境变量中指定的目录中搜索文件。如果在$PATH 中找不到该文件,该命令将在当前目录中查找该文件。
  • 如果给出任何ARGUMENTS,它们将成为FILENAME 的位置参数。
  • 如果FILENAME存在,则源命令退出码为0,否则,如果找不到文件,则返回1

在这些要点中,要关注的一点是second,如果您使用的是#!/bin/bash,则实际上需要为文件提供ABSOLUTE_PATH,如果是,RELATIVE_PATH 只是不起作用你的情况然后我的朋友你只需要将路径更改为ABSOLUTE_FILE_PATH

【讨论】:

    【解决方案5】:

    如果你定义了

        #!/bin/bash
            fun1(){
              echo "Fun1 from file1 $1"
            }
    fun1 Hello
    . file2 
    fun1 Hello
    exit 0
    

    在文件 1 中(chmod 750 文件 1) 和文件2

       fun1(){
          echo "Fun1 from file2 $1"
        }
        fun2(){
          echo "Fun1 from file1 $1"
        }
    

    然后运行 ​​./file2 你会得到 来自file1的Fun1 来自file2的Fun1 惊喜!!!您用 file2 中的 fun1 覆盖 file1 中的 fun1... 为了不这样做,您必须

    declare -f pr_fun1=$fun1
    . file2
    unset -f fun1
    fun1=$pr_fun1
    unset -f pr_fun1
    fun1 Hello
    

    它会保存您之前对 fun1 的定义并使用之前的名称恢复它,删除不需要导入的名称。 每次从另一个文件导入函数时,您可能会记住两个方面:

    1. 你可以用相同的名字覆盖现有的(如果你想要的东西你必须如上所述保留它们)
    2. 导入导入文件的所有内容(函数和全局变量) 当心!这是一个危险的过程

    【讨论】:

      【解决方案6】:

      这是一个非常古老的帖子,我知道。但是我发现即使它位于同一目录中,我也无法获取另一个文件。

      line 3: ./functions.bash: No such file or directory
      

      然后我记得我已经为这种确切情况准备了一个方法,因为我是从一个 ini 文件导入的。所以这是我的解决方案,它允许我从任何地方(显然是源文件)运行程序,而无需对路径进行硬编码。

      app="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
      source $app/functions.bash
      

      我不能把这归功于这个,已经有一段时间了,我不记得我从哪里得到的,否则我会相信他们,但这就是我用来源文件的全部。

      【讨论】:

        【解决方案7】:
        #vi function.sh
        
        #!/bin/bash
        f1() {
            echo "Hello $name"
        }
        
        f2() {
            echo "Enter your name: "
            read name
            f1
        }
        f2
        
        #sh function.sh
        

        这里的函数f2会调用函数f1

        【讨论】:

          最近更新 更多