在 SH 上将 BASH 脚本转换为 运行(通过 BusyBox)
Converting a BASH script to run on SH (via BusyBox)
我有一个 Asus 路由器 运行正在使用最新版本的 FreshTomato - BusyBox 随附。
我需要 运行 一个考虑到 BASH 的脚本 - 它是对 this script 的改编 - 但它无法 运行 并出现此错误: 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 到 sh" 代码转换可能。
我试图创建一个指向 busybox
的 /bin/bash
符号链接,但我遇到了 Read-only file system
错误。
那么,我怎样才能将此脚本发送到我的路由器上的 运行?我只看到两个选项,但我不知道如何实现:
- 让 BusyBox 将脚本解释为 BASH 而不是 SH - 我可以为此使用特定的 shebang 吗?
- 似乎是最快的选择,但前提是 BusyBox 具有 BASH
的“完整”实现
- 更改脚本代码以不使用 BASH 细节。
- 这样比较安全,但是SH没有“收集所有以X开头的变量”,我该怎么做呢?
how can I get this script to run on my router?
很简单,要么:
- 在您的路由器上安装 bash 或
- 将脚本移植到 busybox/posix 兼容 shell。
Make BusyBox interpret the script as BASH instead of SH - can I use a specific shebang for this?
这没有意义。 Busybox 自带 ash
shell 解释器而 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 也不会参与其中。
how can I do it?
确定一个不切实际的最大值,遍历名为 foreign_option_{1...some_max}
的变量,对于每个变量,查看它是否已设置,如果已设置,则继续脚本。
for i in $(seq 100); do
optionvarname="foreign_option_${i}"
#
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 可能会遇到更多问题,因此您可能需要首先考虑替代方案,例如更换路由器)
我有一个 Asus 路由器 运行正在使用最新版本的 FreshTomato - BusyBox 随附。
我需要 运行 一个考虑到 BASH 的脚本 - 它是对 this script 的改编 - 但它无法 运行 并出现此错误: 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 到 sh" 代码转换可能。
我试图创建一个指向 busybox
的 /bin/bash
符号链接,但我遇到了 Read-only file system
错误。
那么,我怎样才能将此脚本发送到我的路由器上的 运行?我只看到两个选项,但我不知道如何实现:
- 让 BusyBox 将脚本解释为 BASH 而不是 SH - 我可以为此使用特定的 shebang 吗?
- 似乎是最快的选择,但前提是 BusyBox 具有 BASH 的“完整”实现
- 更改脚本代码以不使用 BASH 细节。
- 这样比较安全,但是SH没有“收集所有以X开头的变量”,我该怎么做呢?
how can I get this script to run on my router?
很简单,要么:
- 在您的路由器上安装 bash 或
- 将脚本移植到 busybox/posix 兼容 shell。
Make BusyBox interpret the script as BASH instead of SH - can I use a specific shebang for this?
这没有意义。 Busybox 自带 ash
shell 解释器而 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 也不会参与其中。
how can I do it?
确定一个不切实际的最大值,遍历名为 foreign_option_{1...some_max}
的变量,对于每个变量,查看它是否已设置,如果已设置,则继续脚本。
for i in $(seq 100); do
optionvarname="foreign_option_${i}"
#
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 可能会遇到更多问题,因此您可能需要首先考虑替代方案,例如更换路由器)