♨ umask personalizzata per directory con zsh

La gestione della umask nelle shell tradizionali non e' mai stata flessibile, ma sono tempi in cui sempre piu' spesso ci si trova a lavorare in ambienti condivisi dove, sullo stesso filesystem, coesistono aree private e aree di gruppo.

Sarebbe comodo poter dire alla shell: voglio una umask 022 per i file nella mia $HOME, ma voglio 007 per la directory /project.

La scuola zshaolin tramanda la seguente tecnica:

# umask per directory
#
# NOTA: la tabella 'umask_table' e' sequenziale e verra' scelto il primo
# match valido, percio' se si vuole impostare una umask per una directory e per
# una sua sotto directory bisognera' impostare prima quella della sottodirectory.
#
# INOLTRE: il path della directory deve essere racchiuso tra apici e puo' contenere
# white-space.
#
# Esempio:
# umask_table=(
#       '~/Work/FooBar' 022
#       '~/Work' 011
# )

typeset -A umask_table
umask_table=(
        '~/Work' 007
        '~/tmp' 027
        '~/ciao ciao' 011
)

chpwd() {
        local current_umask=$(umask)

        for dir new_umask in ${(kv)umask_table}; do
                if [[ "$PWD" == ${~dir}* ]]; then
                        [[ $current_umask == $new_umask ]] && return
                        echo "[zsh] Switching to '$dir' umask: $new_umask"
                        PREVIOUS_UMASK=$current_umask
                        umask $new_umask
                        return
                fi
        done
        if [[ ! -z $PREVIOUS_UMASK ]]; then
                echo "[zsh] Switching to 'previous' umask: $PREVIOUS_UMASK"
                umask $PREVIOUS_UMASK
                unset PREVIOUS_UMASK
        fi
}

Questa tecnica approfitta della special function chpwd di zsh, che, se definita, viene chiamata ogni volta che la working directory viene cambiata.

Esiste anche una tecnica piu' pulita di definire la umask_table, inventata dagli zshaolin della scuola GRML che utilizza gli zstyle di zsh; la tecnica funziona cosi':

zstyle ':chpwd:profiles:$HOME/Work(|/|/*)' profile work

Con questa tecnica il lookup della corretta usermask non sara' un loop, ma una singola chiamata a zstyle, tipo:

zstyle -s ":chpwd:profiles:${PWD}" profile profile || profile='default'