Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Busybox sh won't execute the bash script

I have a small script called test.sh which prints the value based on the index given.

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

The above code works fine if I execute using bash.

$ bash test.sh 1
31

But I need to execute the same script in an embedded board which has sh as part of Busybox package. When I run the command in that board, it throws an error.

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

I observe that the same error is thrown when I use dash instead of bash in Ubuntu system.

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

Is there any way that I could change the code so that Busybox sh will execute without any errors?

like image 529
Nayab Basha Sayed Avatar asked Nov 26 '25 13:11

Nayab Basha Sayed


2 Answers

Both busybox' sh (which isash) and dash do not support arrays.

You could either write a big if-else or switch case statement, or use the following trick. We simulate an array using a single string with spaces as delimiters.

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

or even more portable:

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

Another workaround is to abuse the script's positional parameters as seen in this answer.

like image 120
Socowi Avatar answered Nov 28 '25 03:11

Socowi


/bin/sh in general does not support arrays, apart from the list of positional parameters.

Let's use that:

#/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"

This first picks out the number from the command line and puts it into pos. Then it sets the positional parameters that you had in your array. By shifting pos - 1 elements off this array, we have the wanted number in $1.

This would work even if the list contained strings with spaces in them, such as 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"

The other way to solve this with /bin/sh is with a case statement:

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
like image 38
Kusalananda Avatar answered Nov 28 '25 03:11

Kusalananda



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!