【问题标题】:Busybox sh won't execute the bash scriptBusybox sh 不会执行 bash 脚本
【发布时间】:2018-11-22 18:07:41
【问题描述】:

我有一个名为test.sh 的小脚本,它根据给定的索引打印值。

#!/bin/sh
days_in_month=(0 31 28 31 30 31 30 31 31 30 31 30 31)
echo "${days_in_month[$1]}"

如果我使用bash 执行,上面的代码可以正常工作。

$ bash test.sh 1
31

但我需要在具有sh 作为Busybox 包的一部分的嵌入式板上执行相同的脚本。当我在该板上运行命令时,它会引发错误。

$ sh test.sh
test.sh: line 2: syntax error: unexpected "("

我观察到当我在 Ubuntu 系统中使用 dash 而不是 bash 时会引发相同的错误。

$ dash test.sh
test.sh: line 2: syntax error: unexpected "("

有什么方法可以更改代码,以便 Busybox sh 执行时不会出现任何错误?

【问题讨论】:

    标签: bash sh busybox dash-shell


    【解决方案1】:

    busybox'sh(即ash)和dash 都支持数组。

    您可以编写一个大的 if-else 或 switch case 语句,或者使用以下技巧。我们使用带有空格作为分隔符的单个字符串来模拟数组。

    cut -d ' ' -f "$1" <<< "31 28 31 30 31 30 31 31 30 31 30 31"
    

    甚至更便携:

    echo "31 28 31 30 31 30 31 31 30 31 30 31" | cut -d ' ' -f "$1"
    

    另一种解决方法是滥用脚本的位置参数,如 this answer 所示。

    【讨论】:

    • 完成了工作。谢谢。但是,我仍然担心如何在破折号中使用数组来实现这一点。
    • @NayabBashaSayed dash does not support arrays.
    • 哦。谢谢..请您详细说明此信息的答案。我会将其标记为已接受的答案。
    • 请注意,here-strings 也是对标准 sh shell 的扩展,我有点惊讶ash 支持它们。跨度>
    • 您可以将here字符串替换为单行here文档,它与POSIX兼容。
    【解决方案2】:

    /bin/sh 通常不支持数组,除了位置参数列表。

    让我们使用它:

    #/bin/sh
    
    pos=$1
    
    if [ "$pos" -lt 1 ] || [ "$pos" -gt 12 ]; then
        printf 'No such month: %s\n' "$pos" >&2
        exit 1
    fi
    
    set -- 31 28 31 30 31 30 31 31 30 31 30 31
    shift "$(( pos - 1 ))"
    printf '%s\n' "$1"
    

    这首先从命令行中挑选出数字并将其放入pos。然后它设置您在数组中的位置参数。通过将 pos - 1 元素从这个数组中移出,我们在 $1 中得到了想要的数字。

    即使列表中包含带有空格的字符串,例如 in

    #/bin/sh
    
    pos=$1
    
    if [ "$pos" -lt 1 ] || [ "$pos" -gt 12 ]; then
        printf 'No such month: %s\n' "$pos" >&2
        exit 1
    fi
    
    set -- "thirty one" "twenty eight" "thirty one" etc.
    shift "$(( pos - 1 ))"
    printf '%s\n' "$1"
    

    使用/bin/sh 解决此问题的另一种方法是使用case 语句:

    case $1 in
        2)
            echo 28 ;;
        4|6|9|11)
            echo 30 ;;
        1|3|5|7|8|10|12)
            echo 31 ;;
        *)
            print 'No such month: %s\n' "$1" >&2
            exit 1
    esac
    

    【讨论】:

      【解决方案3】:

      在这种情况下使用eval 非常有用。您可以简单地定义几个函数:

      assign_element() { eval "__ARR_$1_$2=\"$3\""; }
      get_element() { eval "echo \$__ARR_$1_$2"; }
      

      你可以这样做:

      assign_element days_of_week 1 31
      

      $ get_element days_of_week 1
      31
      

      当然,所有这些实际上都是创建单独的变量,其名称与数组名称和元素相关的固定格式。根据情况,您可以使这些变量名称更复杂以避免冲突,并且没有理由将索引设为数字。使用小脚本将值列表分配给数字索引以更接近您的原始问题也很简单,例如:

      assign_list() {
          local N=0 NAME=$1
          while [ -n "$2" ] ; do
              assign_element "$NAME" $N "$2"
              shift
              N=$((N + 1))
          done
      }
      

      那么你最初的问题就变成了:

      $ assign_list days_in_month 0 31 28 31 30 31 30 31 31 30 31 30 31
      $ get_element days_in_month 1
      31
      

      【讨论】:

        猜你喜欢
        • 2014-07-07
        • 1970-01-01
        • 2016-07-29
        • 2022-08-23
        • 1970-01-01
        • 2013-11-01
        • 2014-02-15
        • 2016-07-23
        • 1970-01-01
        相关资源
        最近更新 更多