在Bash或Shell脚本中如何实现函数声明的前向引用?

112

bash中是否有类似于C / C++中广为人知的前向声明或类似的解决方法?

或者之所以没有这样的东西,是因为它总是一次性执行(逐行执行)?

如果没有前向声明,该怎么办才能让我的脚本更易于阅读呢?我的脚本很长,在开头混合了函数定义和全局变量,使得我的脚本看起来很丑陋,难以阅读/理解。我想学习一些此类情况下公认的最佳实践。


例如:

# something like forward declaration
function func

# execution of the function
func

# definition of func
function func
{
    echo 123
}
3个回答

218

很好的问题。我大多数脚本都使用这样的模式:

#!/bin/bash

main() {
    foo
    bar
    baz
}

foo() {
}

bar() {
}

baz() {
}

main "$@"

你可以从上往下读代码,但它实际上不会开始执行直到最后一行。通过将"$@"传递给main()函数,您可以像通常一样访问命令行参数$1$2等。


3
你好,你在例子中提到需要共享的数据应该如何进行结构化?通常我会将它放在脚本的顶部。当使用函数时,这种方法仍然适用吗?或者将全局数据放在主函数中,然后将其作为参数传递给foo/bar/baz,这样做是否更好?哪种方式是最佳实践? - bodacydo
4
我喜欢使用论据。如果不行的话,我会在main函数中或者紧接着main函数的一个函数(例如setupparseArguments)中设置全局变量。我避免将全局变量设置在main函数上方,因为代码不应该超出main函数的范畴。 - John Kugelman
这似乎有些类似于 Python 中的 if __name__ == "__main__": main() 的作用。 - Sergiy Kolodyazhnyy
当使用像Bats这样的工具测试脚本时,将所有内容分解为函数也非常棒,这使得测试单个组件变得更加容易。另请参见博客文章 - dragon788

33

当我的bash脚本变得太庞大时,我会使用一个包含机制:

文件allMyFunctions

foo() {
}

bar() {
}

baz() {
}

文件 main:

#!/bin/bash

. allMyfunctions

foo
bar
baz

35
个人而言,当一个 shell 脚本开始超过一个文件时,我倾向于转换到另一种语言;-) - Joachim Sauer
使用 source allMyfunctions 不是更好吗? - halpdoge
4
@pydoge:source不符合POSIX标准。bashsource定义为.的别名:它们在功能上是等效的。 - mouviciel

0

你可以在脚本中包含自身的源代码部分:

#!/bin/bash
. <( sed -n '/^#SOURCE-BEGIN/,/^#SOURCE-END/{//!p;}' $0 )
greeting "$@"
foo hey

#SOURCE-BEGIN
greeting() {
  for i in "$@"
  do
    echo ">[$i]"
  done
}

foo() {
  echo in foo
  echo "arg passed in: $1"
}
#SOURCE-END

echo good bye

$ ./myscript.sh hello world "one string"
>[hello]
>[world]
>[one string]
in foo
arg passed in: hey
good bye

我使用进程替换(<(....))来获取sed命令的输出。 sed的语法来源于这里,搜索What about the classic sed solution?


这是狂野 - undefined

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