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

将BASH脚本转换为在SH上运行(通过BusyBox),bash,sh,parameter-expansion,Bash,Sh,Parameter Expansion,我有一台华硕路由器,运行的是BusyBox附带的最新版本 我需要运行一个用BASH编写的脚本—它是的一个改编版—但由于以下错误而无法运行:第41行:语法错误:错误替换 使用以下错误检查脚本: Line 41: for optionvarname in ${!foreign_option_*} ; do ^-- SC3053: In POSIX sh, indirect expansion is undefined.

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

我需要运行一个用BASH编写的脚本—它是的一个改编版—但由于以下错误而无法运行:
第41行:语法错误:错误替换

使用以下错误检查脚本:

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.
以下是导致问题的线路:

${!foreign_option_*}中optionvarname的
;第41行
option=“${!optionvarname}”第42行
#用$option做一些事情。。。
完成
如果我的理解是正确的,那么原始脚本只是对所有名称以
foreign\u option\u开头的变量执行一些操作

但是,据我所知,
${!foreign_option_*}
${!optionvarname}
构造都是特定于BASH的,不符合POSIX,因此不可能直接进行“BASH到sh”的代码转换

我试图创建一个指向
busybox
/bin/bash
符号链接,但出现了
只读文件系统
错误

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

  • 让BusyBox将脚本解释为BASH而不是SH-我可以为此使用特定的shebang吗?
    • 似乎是最快的选择,但前提是BusyBox有一个BASH的“完整”实现
  • 修改脚本代码以不使用BASH细节。
    • 这是比较安全的,但是因为SH没有“收集以X开头的所有变量”,我该怎么做呢
  • 如何让此脚本在路由器上运行

    这很容易,或者:

    • 在路由器上安装bash或
    • 将脚本移植到busybox/posix兼容的shell
    让BusyBox将脚本解释为BASH而不是SH-我可以为此使用特定的shebang吗

    那没有道理。Busybox附带了
    ash
    shell解释器,bash就是bash。Bash可以解释Bash扩展,而ash不能解释它们。你不能“让爱管闲事的人解释bash”——汽车不能飞,飞机就是为了这个。如果你想让汽车飞起来,你可以给它加上翅膀,让它飞得更快。
    makebusybox将脚本解释为BASH而不是SH
    的答案是:修补BusyBox并在其中实现所有BASH扩展

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

    我怎么做

    确定一个不切实际的最大值,迭代名为
    foreign\u option\u{1…some\u 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;
    
    如果运气好的话,也许您可以使用
    设置
    输出。如果任何变量包含值为换行符+与正则表达式匹配的字符串,则以下操作将失败:

    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脚本移到BuyBox,因此您可能首先考虑替换路由器之类的选项)

    如何>代码> SETGRIP-E“^ x”< /代码>以从<代码> x>代码>开始收集变量名?<代码> SH < /C>不提供可变的间接方向,如<代码> ${opopraveNord}。
    尝试计算其名称存储在
    选项varname
    中的变量。这是一个bash特有的特性,会导致“糟糕的替换”。。。请注意您的错误消息“在POSIX sh中,间接扩展是未定义的。”--这就是它告诉您的……。@DavidC.Rankin:我解决了这个问题,但遗憾的是,我并不精通
    bash
    /
    sh
    差异和复杂性,以便能够进行正确的转换,因此请求我的路由器提供帮助,
    /bin/sh
    是指向
    /bin/busybox
    的符号链接。我将尝试“不切实际的最大值”建议(而不是
    set
    one),我会让你知道它是如何进行的。