1

I have created the following function to memoize any command:

# zsh
(( $+functions[ec] )) || {
    ec() print -r -- "$@"
    ecerr() { ec "$@" 1>&2 }
    ecdbg() ecerr "$@"
    gq() { ec "${(q+@)@}" }
}
(( $+functions[dvar] )) || function dvar() {
        local pre=''
        test -z "$2" || pre="CODE $2 | "
        echo "$pre$(typeset -p "$1" 2>&1)"
        echo "$pre$1 in env: $(printenv "$1")"
    }
## Aliases
## Vars
memoi_expire=$(( 3600*24*7 ))
## Functions
function mem() { memoi_expire=$(( $1 * 60 )) reval "$@" }
function memoi-eval() {
    typeset -Ag memoi_stdout
    typeset -Ag memoi_stderr
    typeset -Ag memoi_timestamp
    typeset -Ag memoi_exit
    typeset -Ag memoi_debug

    dvar memoi_exit
    local now="$(date +%s)"
    local cmd="$(gq "$@")"
    re dvar cmd memoi_expire memoi_timestamp now
    { (( $+memoi_timestamp[$cmd] )) && ecdbg ice0 && { (( memoi_expire == 0 )) || { ((memoi_expire >= 0 )) && ecdbg fire0 && (( (now - memoi_timestamp[$cmd]) <= memoi_expire )) && ecdbg fire1 } } && ecdbg monkey0 } && {
        dact fsay using memoi
        ecdbg Using memoi: "$cmd"
        test -n "$memoi_stdout[$cmd]" && ec "$memoi_stdout[$cmd]"
        test -n "$memoi_stderr[$cmd]" && ecerr "$memoi_stderr[$cmd]"
        (exit 0)
   } || {
        dact fsay memoi not fresh enough
        ecdbg 'Evaling (no memoi): ' "$cmd"
        local errfile="$(mktemp)"
        memoi_stdout[$cmd]="$(eval "$cmd" 2>"$errfile")"
        memoi_exit[$cmd]=$?
        memoi_stderr[$cmd]="$(<$errfile)"
        \rm "$errfile"
        memoi_timestamp[$cmd]="$(date +%s)"
        test -n "$memoi_stdout[$cmd]" && ec "$memoi_stdout[$cmd]"
        test -n "$memoi_stderr[$cmd]" && ecerr "$memoi_stderr[$cmd]"
    }
    dvar memoi_exit
    # dvar memoi_stdout
    memoi_debug[$cmd]=yes
    memoi_debug[apple]=yes
    return $memoi_exit[$cmd]
}

It works, but my problem is that the shell is full of forking, and the forked subshells can't set variables of the mother shell. Thus,

memoi-eval echo hi

works, but

memoi-eval echo hi2 |cat doesn't. What are my options?

I have found the following workaround for process substitution (Which loses some whitespace):

local some_var
nulterm some_command |read -d '' -r some_var
# deps
reval () {
    ecdbg revaling "$(gq "$@")"
    eval "$(gq "$@")"
}
nulterm () {
    reval "$@"
    ec $'\0'
}

But avoiding pipes is quite hard ... Any elegant way to do it? I imagine it should be possible with fifos but it'd make coding very hard.

Should I use an in-memory key-value store like redis?

Your Answer

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

Browse other questions tagged or ask your own question.