Search code examples
bashlist-comprehension

List comprehension in pure BASH?


Is it possible to do LC like in python and other languages but only using BASH constructs?

What I would like to be able to do, as an example is this:

function ignoreSpecialFiles()
{
    for options in "-L" "-e" "-b" "-c" "-p" "-S" "! -r" "! -w"; do
        if [[ $options "$1" -o $options "$2" ]];then
            return $IGNORED
        fi
    done
}

instead of using code like this:

if [[ -L "$1" -o -e "$1" -o -b "$1" -o -c "$1" -o -p "$1" -o -S "$1" -o\
! -r "$1" -o ! -w "$1" ]]

Do you know of any recipes for simulating LC like this??

Edit:

A more LC specific example:

M = [x for x in S if x % 2 == 0] #is python

what is the most pythonic way to do the same in bash?

for x in S; do if x % 2 == 0;then (HERE MY HEAD EXPLODES) fi done

Solution

  • Here's a semi-general format for doing the equivalent of LC in bash with arrays:

    outarray=()
    for x in "${inarray[@]}"; do
        if SOMECONDITION; then
            outarray+=(SOMEFUNCTIONOFx)
        fi
    done
    

    Here's your second example in this format:

    s=({1..10})
    echo "${s[@]}"
    # Prints: 1 2 3 4 5 6 7 8 9 10
    m=()
    for x in "${s[@]}"; do
        if (( x % 2 == 0 )); then
            m+=($x)
        fi
    done
    echo "${m[@]}"
    # Prints: 2 4 6 8 10
    

    Here's another example, with a less trivial "function" but without the conditional:

    paths=("/path/to/file 1" "/path/somewhere/else" "/this/that/the other" "/here/there/everywhere")
    filenames=()
    for x in "${paths[@]}"; do
        filenames+=( "$(basename "$x")" )
    done
    printf "'%s' " "${filenames[@]}"
    # Prints: 'file 1' 'else' 'the other' 'everywhere'