转换BASH脚本以在SH上运行(通过BusyBox)



我有一个华硕路由器,运行的是BusyBox附带的最新版本的FreshTomato。

我需要运行一个考虑到BASH的脚本——它是对这个脚本的改编——但它无法运行,并出现以下错误:line 41: syntax error: bad substitution

使用shellcheck.net检查脚本会产生以下错误:

Line 41:
for optionvarname in ${!foreign_option_*} ; do
^-- SC3053: In POSIX sh, indirect expansion is undefined.
^-- SC3056: In POSIX sh, name matching prefixes are undefined.

Line 42:
option="${!optionvarname}"
^-- SC3053: In POSIX sh, indirect expansion is undefined.

这些是造成问题的线路:

for optionvarname in ${!foreign_option_*} ; do   # line 41
option="${!optionvarname}"                   # line 42
# do some stuff with $option...
done

如果我的理解是正确的,那么原始脚本只是对名称以foreign_option_开头的所有变量执行一些操作

然而,就我所能确定的,${!foreign_option_*}${!optionvarname}构建体都是BASH特异性的,并且不符合POSIX,因此不存在直接的";bash to sh";代码转换是可能的。

我试图创建一个指向busybox/bin/bash符号链接,但我得到了Read-only file system错误。

那么,我怎样才能让这个脚本在我的路由器上运行呢?我只看到两个选项,但我不知道如何实现:

  1. 让BusyBox将脚本解释为BASH而不是SH-我可以为此使用特定的shebang吗?
    • 看起来是最快的选项,但前提是BusyBox有一个";完整的";BASH的实施
  2. 将脚本代码更改为不使用BASH细节。
    • 这更安全,但由于没有"收集以X"开始的所有变量;对于SH,我该怎么做

如何让这个脚本在我的路由器上运行?

也很简单:

  • 在路由器上安装bash或
  • 将脚本移植到busybox/posix兼容的shell

让BusyBox将脚本解释为BASH而不是SH-我可以为此使用特定的shebang吗?

这没有道理。Busybox带有ashshell解释器,bash就是bash。Bash可以解释Bash扩展,而ash不能解释它们。你不能"使busybox解释bash"-汽车不会飞,飞机就是这样。如果你想让汽车飞起来,你就给它加上翅膀,让它飞得更快。Make BusyBox interpret the script as BASH instead of SH的答案是:修补busybox并在其中实现所有bash扩展

Shebang用于在不同的解释器下运行文件。使用#!/bin/bash将调用bash,这将与任何与busybox相关的内容无关,并且busybox不会参与其中

我该怎么做?

决定一个不切实际的最大值,对名为foreign_option_{1...some_max}的变量进行迭代,对于每个变量,查看它是否已设置,如果已设置,则协同脚本。

for i in $(seq 100); do
optionvarname="foreign_option_${i}"        
# https://stackoverflow.com/questions/3601515/how-to-check-if-a-variable-is-set-in-bash
if eval "[ -z "${${optionvarname}+x}" ]"; then continue; fi;

如果有足够的运气,也许您可以使用set输出。如果任何变量包含的值为换行符+与正则表达式匹配的字符串,则以下操作将失败:

for optionvarname in $(set | grep -o '^foreign_option_[0-9]+=' | sed 's/=//'); then

eval:可以很容易地替代间接扩展

eval "option="$${optionvarname}""

如果你真的不能在路由器上安装Bash,这里有一个可能的解决方法,它似乎对我在Qnap-NAS:上的BusyBox中有效

foreign_option_one=1
foreign_option_two=2
for x in one two; do
opt_var=foreign_option_${x}
eval "opt_value=$$opt_var"
echo "$opt_var = $opt_value"
done

(但在将Bash脚本移动到busybox时,您可能会遇到更多问题,因此您可能需要首先考虑替代方案,如更换路由器(

相关内容

最新更新