Reputation: 617
I'm trying to build a zsh function that returns an output based on a time interval. Initially the "You're thirsty" condition is true, but after changing the variable thirsty
through the command line and setting it to false, the initial if statement goes through, but the variable thirsty
in it doesn't change the global variable thirsty
. Is there a way to modify the global variable thirsty
?
thirsty=
last_time=
drink_water() {
echo -n "$thirsty"
if [[ $thirsty == false ]]; then
last_time="$[$(date +%s) + 10]"
thirsty=true
echo -n "${last_time} $(date +%s) ${thirsty}"
elif [[ $[last_time] -lt $(date +%s) ]]; then
echo -n "π§ You're thirsty"
fi
}
Upvotes: 3
Views: 1931
Reputation: 619
You can use Zsh Hooks.
Hooks avoid the issues of command substitution here because they run in the same shell, rather than a subshell.
drink_water_prompt=
thirsty=
last_time=
drink_water_gen_prompt() {
drink_water_prompt="$thirsty"
if [[ $thirsty == false ]]; then
last_time="$[$(date +%s) + 10]"
thirsty=true
drink_water_prompt+="${last_time} $(date +%s) ${thirsty}"
elif [[ $[last_time] -lt $(date +%s) ]]; then
drink_water_prompt+="π§ You're thirsty"
fi
}
autoload -Uz add-zsh-hook
add-zsh-hook precmd drink_water_gen_prompt
PROMPT='${drink_water_prompt}'
These also allow more than one precmd()
function.
Upvotes: 0
Reputation: 295815
Since your code is actually called from:
PROMPT='$(drink_water)'
...everything it contains is run in a subprocess spawned as part of this command substitution operation ($()
is a "command substitution": It creates a new subprocess, runs the code given in that subprocess, and reads the subprocess's output). When that subprocess exits, changes to variables -- even global variables -- made within the subprocess are lost.
If you put your update code directly inside a precmd
function, then it would be run before each prompt is printed but without a command substitution intervening. That is:
precmd() {
local curr_time=$(date +%s) # this is slow, don't repeat it!
if [[ $thirsty = false ]]; then
last_time="$(( curr_time + 10 ))"
thirsty=true
PROMPT="$last_time $curr_time $thirsty"
elif (( last_time < curr_time )); then
PROMPT="π§ You're thirsty"
fi
}
Of course, you can set your PROMPT with a command substitution, but updates to variable state have to be done separately, outside that command substitution, if they are to persist.
Upvotes: 4