Shell脚本如何引用其他Shell脚本以及最佳调用方式

3

我一直想问这个问题,但不想冒着声誉受损的风险,但现在我真的需要一些直接的输入。我是一个 Linux 新手,正在使用 Raspberry Pi 搭建 LAMP 服务器,并喜欢创建所有安装命令的 shell 文件,但我也喜欢保持模块化,例如:

#!/bin/sh
#LAMPinstall.sh
./apacheinstall.sh
./mysqlinstall.sh
./phpinstall.sh

我习惯于编写环境中这样的调用非常简单,但是这个脚本的明显问题是它需要在调用时当前工作目录为脚本所在的目录。

我进行了大量关于绝对路径与相对路径、源码引用与调用、bash与shell以及引用脚本路径等Linux特定内容方面的阅读,试图找到一个解决超出当前工作目录相对路径调用的方法,但是最终并没有取得满意的解决方案,或许永远也不会。目前,我使用存储在变量中的绝对路径,例如:

#!/bin/sh
#LAMPinstall.sh
thisdir=/path/to/scripts
${thisdir}/apacheinstall.sh
${thisdir}/mysqlinstall.sh
${thisdir}/phpinstall.sh

即使每次路径改变都需要修改脚本,但我仍需使用这种方式来调用shell脚本。所以我的问题更多是一个最佳实践的问题,而不是请求解决特定问题的方案(尽管它是一个具体问题),以下问题需一起考虑,而不是像我所读到的每个单独的文章和问题:

  1. 使用我目前的方式组织调用shell脚本是不是一个坏主意?
  2. 使用类似于$(dirname "$0")这样的内容引用一个脚本的路径是不是一个坏主意?如果是,那么你如何维护多个shell文件的组织结构?
  3. 在考虑问题#2时,是否重要考虑他人可能对脚本的所有可能用法(例如:是否存在子目录并被源码引用)?还是说只需说“只能调用此脚本,如果有人滥用则由他们自负”。对不起,我表达得不够好。

如果这是一个幼稚的问题,请见谅,我只是想听听您的意见。


下面有一个很好的答案,但我的第一想法是“不要过度思考这个问题”。试图编写能够包容您可以想象到(或遇到的)每种可能错误的代码,可能会使您远离真正目的。您在第3点中的总结是正确的方法,“这就是这个程序的使用方式”(并在注释、使用消息和可能的手册中很好地记录它(对于安装程序而言不需要手册))。祝你好运! - shellter
是的,我同意,这是我的一个坏习惯,特别是考虑到应用程序的小范围。最近我也陷入了类似的兔子洞,关于sed(请参见https://dev59.com/jUIEtIcB2Jgan1znuMMx),最终,“错误处理”是一个疯狂的“假设?”情景,我可以轻松地忽略它。我的想法总是“至少我学到了很多东西”,但是学习的努力与需求不成比例。我的最终目标是将这些安装和配置脚本打包,以便通过rc local在新安装上运行,以便我的环境可以立即使用。 - spiff
我并不是说不要试着提高你日常编码的质量(我认为你也不是这个意思)。挑战自己总是好的。(以上纯属个人意见)祝好运。 - shellter
发现了这个深入讨论此问题的帖子,但似乎用户询问的是关于shell的,而大多数答案都是关于bash的。https://dev59.com/ZHVC5IYBdhLWcg3wnCWA - spiff
1个回答

2

Shell并没有提供非常复杂的维护相关脚本库的功能。常见的技巧包括您所建议或至少暗示的内容。

#!/bin/sh
here="$(dirname "$0")"
"$here"/apacheinstall.sh
"$here"/mysqlinstall.sh
"$here"/phpinstall.sh

或者类似这样

#!/bin/sh
PATH="$(dirname "$0")":$PATH
apacheinstall.sh
mysqlinstall.sh
phpinstall.sh

或者要求用户设置适当的变量:

#!/bin/sh
: ${LAMP_INSTALL_PATH?Need this variable to be set}
"$LAMP_INSTALL_PATH"/apacheinstall.sh
"$LAMP_INSTALL_PATH"/mysqlinstall.sh
"$LAMP_INSTALL_PATH"/phpinstall.sh

一种类似的技术是默认使用像 /usr/local/lib/lampinstall 这样的路径,并允许用户通过类似的方式覆盖此路径。
#!/bin/sh
: ${LAMP_INSTALL_PATH=/usr/local/lib/lampinstall}
"$LAMP_INSTALL_PATH"/apacheinstall.sh
"$LAMP_INSTALL_PATH"/mysqlinstall.sh
"$LAMP_INSTALL_PATH"/phpinstall.sh

当然,对于任何一个相当现代的发行版来说,解决这个特定问题的真正方法是将你需要的东西打包成一个软件包,然后安装它。例如,在Debian平台上,
sudo apt install -y local-lamp-stuff

在这里,您只需要创建local-lamp-stuff.deb并将其Depends:设置为您需要的先决条件包。


很棒的答案,只是希望您也能向我们展示如何制作package.deb和依赖项;-)!祝大家好运。 - shellter
我自己最喜欢的行内配置技巧使用默认值,就像上面代码块中显示的那样,但是要知道你可以在命令行上覆盖该值,方法是在命令之前添加所需的值,例如 LAMP_INSTALL_PATH=/different/path ./installer.sh。这也使得在代码中包含调试变量更简单,而不必从命令行处理它们。只需 dbg=true dbg2=false ./installer.sh。祝大家好运! - shellter
对于一个简单的.deb软件包,它只是拉取一堆依赖项,请尝试使用equivs。如果要提供本地值以覆盖默认软件包配置,请查看debconf预设。 - tripleee
我会研究创建自定义的deb软件包,谢谢。 - spiff

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