1

the following function in shell script only loops through the first element of the array when called on an array, what's wrong?

#!/bin/sh

in_array(){
    a=$2
    echo ${#a[@]}
    for (( i = 0; i < ${#a[@]} ; i++ ))
    do
        echo ${a[$i]}
        if [ $1 = ${a[$i]} ]
            then
            return 1
        fi
    done
    return 0
}

exclude_dirs=( aaa bbb )
echo ${#exclude_dirs[@]}
in_array home $exclude_dirs
1
  • what is the value of array a? Commented Apr 26, 2011 at 9:18

2 Answers 2

1

There are 2 problems. The first is that sh does not support arrays, so your shebang should be changed to a shell that does. (eg, #!/bin/bash). The second problem is more substantial. Arrays are not first class objects in bash (they may be in other shells but I'm going to answer the question for bash, since sh is often bash in many Linux distros and I'm using my crystal ball to determine that you meant bash when you said #!/bin/sh). You can get what you want by using eval. Change your function to something like this:

in_array(){
    a=$2
    eval "for i in \${$a[@]}; do
        echo \$i
        test $1 = \$i && return 1
    done"
    return 0
}

and invoke it without a '$'.

in_array home exclude_dirs

Also, I would strongly recommend inverting the return values. (return 0 if $1 appears in the array, and return 1 if it does not). Either that, or change the function name to "not_it_array". That will allow you to write things like:

if in_array home exclude_dirs; then echo home is excluded; fi

(or use a short circuiting &&). Remember that in sh, 0 is success, and non-zero is failure.

Of course, it would be easier to pass the array by passing all of the values rather than passing the name:

#!/bin/bash

in_array(){
    el=$1
    shift
    while test $# -gt 0; do
        test $el = $1 && return 0
        shift
    done
    return 1
}

exclude_dirs=( aaa home bbb )
in_array home ${exclude_dirs[@]} && echo home is excluded
Sign up to request clarification or add additional context in comments.

1 Comment

I found that I have to pass all the values of the array for it to work, if i JUST pass the name, in_array only loops through the first value
0

William is right that you can't use arrays in Bourne Shell, but you shouldn't be using eval either. To avoid it you could just simplify your parameter structure:

#!/bin/sh

in_array(){
    search_path="$1"
    shift

    while [ -n "${1+defined}" ]
    do
        if [ "$1" = "$search_path" ]
        then
            return 0
        fi
        shift
    done
    return 1
}

in_array foo aaa bbb && echo fail test 1
in_array foo foo bar || echo fail test 2
in_array foo bar foo || echo fail test 3
in_array foo foobar && echo fail test 4
in_array foo barfoo && echo fail test 5
in_array foo "foo bar" && echo fail test 6
in_array "foo bar" "foo bar" "baz ban" || echo fail test 7
true

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.