4
\$\begingroup\$

I have a script that contains two shell functions:

runhaskells() {
    local DIR=$PWD
    local TARGET="cabal.sandbox.config"
    while [[ ! -e $DIR/$TARGET -a $DIR != "/" ]]; do
        DIR=$(dirname $DIR)
    done
    if [[ $DIR != "/" ]]; then
        local DB=$(sed -ne '/^package-db: */{s///p;q;}' "$DIR/$TARGET")
        runhaskell -no-user-package-db -package-db="$DB" "$@"
    else
        runhaskell "$@"
    fi
} 

ghcs() {
    local DIR=$PWD
    local TARGET="cabal.sandbox.config"
    while [[ ! -e $DIR/$TARGET -a $DIR != "/" ]]; do
        DIR=$(dirname $DIR)
    done
    if [[ $DIR != "/" ]]; then
        local DB=$(sed -ne '/^package-db: */{s///p;q;}' "$DIR/$TARGET")
        ghc -no-user-package-db -package-db="$DB" "$@"
    else
        ghc "$@"
    fi
} 

which obviously is a repeat of each other except for the fact that it calls a different program in each function. The first function calls the runhaskell program while the second function calls the ghc program.

How can I DRY this script (either zsh or bash syntax is fine for me) with the end goal that I should be able to call either function at the command line?

\$\endgroup\$
0
3
\$\begingroup\$

Two simple bash solutions I can think of are:

  1. Use a shell script and $0/$BASH_SOURCE to determine the calling name and a symlink from one name to the other.

  2. Two small wrapper functions.

    h() {
        local DIR=$PWD
        local TARGET="cabal.sandbox.config"
        while [[ ! -e $DIR/$TARGET -a $DIR != "/" ]]; do
            DIR=$(dirname $DIR)
        done
        if [[ $DIR != "/" ]]; then
            local DB=$(sed -ne '/^package-db: */{s///p;q;}' "$DIR/$TARGET")
            set -- "${@:1:1}" -no-user-package-db -package-db="$DB" "${@:2}"
            # or this is the order of original arguments and added arguments don't matter
            set -- "$@" -no-user-package-db -package-db="$DB"
        fi
    
        "$@"
    }
    
    runhaskells() {
        h runhaskell "$@"
    }
    
    ghcs() {
        h ghc "$@"
    }
    

Slightly DRYier version of the above which uses bash's FUNCNAME array.

    h() {
        local DIR=$PWD
        local TARGET="cabal.sandbox.config"
        while [[ ! -e $DIR/$TARGET -a $DIR != "/" ]]; do
            DIR=$(dirname $DIR)
        done
        if [[ $DIR != "/" ]]; then
            local DB=$(sed -ne '/^package-db: */{s///p;q;}' "$DIR/$TARGET")
            set -- "${@:1:1}" -no-user-package-db -package-db="$DB" "${@:2}"
            # or this is the order of original arguments and added arguments don't matter
            set -- "$@" -no-user-package-db -package-db="$DB"
        fi

        "${FUNCNAME[1]%s}" "$@"
    }

    runhaskells() {
        h "$@"
    }

    ghcs() {
        h "$@"
    }
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.