Home > Net >  Functional Programming with Bash
Functional Programming with Bash

Time:09-10

How would I implement something similar to functional programming within bash?

I have a function:

requestPassword(){
    
    passwordValidated=false

    while [ "$passwordValidated" = "false" ];do
         tput clear
         [ -n "$infomsg" ] && echo -e "$infomsg" >&2
         [ -n "$errmsg" ] && echo -e "$errmsg" >&2
         read -s -p "some prompt:" pass >&2
         errmsg=$()#do some validation
         [ -n "$errmsg" ] && continue
         passwordValidated=true
    done
    echo "$pass"
}

But I want to make it as generic as possible to work with different systems

Maybe I want to ask the password for an encrypted file Maybe I want to ask the password for a system user Maybe I want to use this function to request a new password from a user

The idea would be that I could pass this function a function that takes in a pass parameter and only outputs something if validation failed

CodePudding user response:

This is my solution. Please feel free to add any more insight you may have on this topic

requestPassword(){
    infomsg="$1"
    passwordValidated=false

    while [ "$passwordValidated" = "false" ];do
        tput clear
        [ -n "$infomsg" ] && echo -e "$infomsg" >&2
        [ -n "$errmsg" ] && echo -e "$errmsg" >&2
        read -s -p "some prompt:" pass >&2
        errmsg=$(dynPasswordValidation "$pass")
        [ -n "$errmsg" ] && continue
        passwordValidated=true
   done
   echo "$pass"
}

You would then have other functions that would call this function for specific password requests but would define dynPasswordValidation function prior to the call like so:

requestCurrentEncryptedFilePassword(){
    infomsg="Requesting password for encrypted file"
    
    dynPasswordValidation(){
        [ -n "$(openssl $encalg -d -in $encfile -pass "pass:$1" 2>&1>/dev/null)" ] && echo "Looks like that password didn't work" && return
    }
    pass="$(requestPassword "$infomsg")"
}


requestNewEncryptedFilePassword(){
    infomsg="Requesting new password for encrypted file"
    dynPasswordValidation(){
        pass="$1"
        echo >&2
        read -p -s "veri prompt" pass_veri >&2
        echo >&2
        [ "$pass" != "$pass_veri" ] && echo "Looks like the passwords didn't match" && return
        [ -n "$(#run the password through a set of password rules)" ] && echo "Looks like the password is not up to snuff..." && return
    }
    pass="$(requestPassword "$infomsg")"
}

CodePudding user response:

You can pass a function name as an argument

requestPassword(){
    local infomsg="$1"
    local validator=${2:-the_default_validator_function}
    # ...
    local errmsg
    errmsg=$( "$validator" "$pass" )
    # ...
}

then

# a valid "foobar" password contains the substring "foo"
foobarPasswordValidator() { [[ $1 == *foo* ]]; }

pass=$(requestPassword "Enter your FooBar password" foobarPasswordValidator) 

If you don't have a default validator, use : or true -- they accept arguments, ignore them(1) and return a "success" exit status.


(1) ignored after any parameter expansions have occurred

  • Related