Default umaks on macOS is 0077
, which is different with most Linux distributions.
There're pros and cons about this very decision made by Apple. For the good
part, temporary files generate under /tmp
, $TMPDIR
are accessible
by the user himself only. These locations could be alternatives to $XDG_RUNTIME_DIR
.
While, the problem is that since the new files are accessible by yourself only, it's inconvenient to share files with other users.
It's easy to change umask globally with a LauchAgent, or change it for shells only in the shell initialization files. But the solution I provide is more flexible, the umask is set per-directory with the help of direnv.
The solution is based on zimbatm's answer from direnv issue #509.
I improved zimbatm's code for macOS, where the default umask value is 0077
.
# example .envrc file
export UMASK=0022
function _umask_hook {
if [[ -n $UMASK ]]; then
umask "$UMASK"
elif [[ $OSTYPE == darwin* ]]; then
umask 0077
else
umask 0022
fi
}
# To make the code more reliable on detecting the default umask
function _umask_hook {
# Record the default umask value on the 1st run
[[ -z $DEFAULT_UMASK ]] && export DEFAULT_UMASK="$(builtin umask)"
if [[ -n $UMASK ]]; then
umask "$UMASK"
else
umask "$DEFAULT_UMASK"
fi
}
# zsh hooks
# trigger _umask_hook once working dir is changed
# precmd is not enough, cause it may not be triggered when cwd is changed by ZLE widget
add-zsh-hook chpwd _umask_hook
# make sure _umask_hook is run on startup
add-zsh-hook precmd _umask_hook
# bash
# Append `;` if PROMPT_COMMAND is not empty
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND;}_umask_hook"
For the time being, direnv hook initialization for zsh doesn't support chpwd
hook. If the pull request GH-514 has not been merged when you see this page. Please comment out eval "$(direnv hook zsh)"
and hook direnv
on chpwd
manually with following code,
if (( $+commands[direnv] )) && ! (( $+functions[_direnv_hook] )); then
_direnv_hook() {
eval "$(command "direnv" export zsh)";
}
typeset -agU precmd_functions;
if [[ -z ${precmd_functions[(r)_direnv_hook]} ]]; then
precmd_functions=( _direnv_hook ${precmd_functions[@]} )
fi
typeset -agU chpwd_functions;
if [[ -z ${chpwd_functions[(r)_direnv_hook]} ]]; then
chpwd_functions=( _direnv_hook ${chpwd_functions[@]} )
fi
fi
In fact, adding _umaks_hook
, _direnv_hook
into precmd
is redundant, cause hooking them onto chpwd
is enough. The only problem is that, chpwd
is not run on shell startup. A solution is here: Trigger chpwd Hook on Startup.
chpwd
Executed whenever the current working directory is changed.
precmd
Executed before each prompt. Note that precommand functions are not re-executed simply because the command line is redrawn, as happens, for example, when a notification about an exiting job is displayed.