I'm tired of forgetting to run some commands before and others after a process. So I decided to give this responsibility to the terminal. Why not?
In ZSH we have two hooks preexec
(after) and precmd
(before) that can be used to achieve this task.
Validations
We need two variables, one to know if the process was quite early to not run the precmd
(before) hook and another to know which command is running actually.
Open ~/.zshrc
file and add these variables to the script.
local quit="y" local cmd=""
I always forgot to run npm run build
command before npm publish
. So we are going to create a function before_validation
to show a message to confirm if we had run the command before.
cancel(){ echo "\e[43m\e[30mALERT:\e[0m Did you run \e[1m'$1'\e[0m command before?" echo "\e[32m[ANY] = Continue \e[0m| \e[31m[Ctrl+c] = Cancel \e[0m" read -sk key quit="n" } before_validation(){ local cmd_validation="" local cmd_previous=$(fc -ln -1 | xargs) # Get previous command from history local cmd_current=$(echo $1 | xargs) if [[ "$cmd_current" =~ ^"npm publish" ]]; then cmd_validation="npm run build" elif [[ "$cmd_current" =~ ^"git checkout" ]]; then cmd_validation="git pull" # --- # Add all elif (else if) that you need elif [[ "$cmd_current" =~ ^"your command" ]]; then cmd_validation="command to run before" # --- fi if [[ ! -z $cmd_validation ]]; then if [[ "${cmd_validation}" != "${cmd_previous}" ]]; then cancel $cmd_validation # show cancel alert if is not the previous fi else quit="n" fi }
Currently, there is no warning about dangerous commands. So we are going to create a function danger_validation
to display a warning message and give us a second chance.
danger(){ echo "\e[41m\e[97mDANGER:\e[0m Are you sure? really?" echo "\e[32m[ANY] = Continue \e[0m| \e[31m[Ctrl+c] = Cancel \e[0m" read -sk key quit="n" } danger_validation(){ local cmd_current=$(echo $1 | xargs) if [[ "$cmd_current" =~ ^"rm -rf /" ]]; then danger elif [[ "$cmd_current" =~ ^"git reset --hard HEAD" ]]; then danger elif [[ "$cmd_current" =~ ^"git clean -f -d -x" ]]; then danger # Add all elif (else if) that you need elif [[ "$cmd_current" =~ ^"your command" ]]; then danger # --- fi }
And I also forgot to run npm i
command after git pull origin ...
. So we are going to create a function after_validation
to show a message to confirm if we want to run a command after.
run(){ echo "\e[43m\e[30mALERT:\e[0m Do you want to run \e[1m'$1'\e[0m command after?" echo "\e[32m[Y] = Yes \e[0m| \e[31m[ANY] = Cancel \e[0m" read -sk key if [[ "$key" == "y" ]] || [[ "$key" == "Y" ]]; then echo "\e[32m❯ \e[33mRunning...\e[0m" eval $1 fi } after_validation(){ if [[ "$cmd" =~ ^"git pull origin" ]]; then run "npm i" elif [[ "$cmd" =~ ^"git checkout" ]]; then run "npm i" elif [[ "$cmd" =~ ^"npm run build" ]]; then run "obp" #open build folder alias # --- # Add all elif (else if) that you need elif [[ "$1" =~ ^"your command" ]]; then cancel "command to run after" # --- fi }
Now we need to create, something like a "factory function" that can be associated with the hooks. I preferred this way because we can call more than one function before or after.
pre_validation() { quit="y" && cmd="" [[ $# -eq 0 ]] && return # If there's no input, return. Else... cmd="$1" # Save global for after validation expand_command_line "$@" danger_validation "$@" before_validation "$@" } pos_validation() { [[ -z $cmd ]] && return # If there's no cmd, return. Else... if [[ "$quit" == "n" ]]; then after_validation fi quit="y" }
And here, we are going to associate pre_validation
function with preexec
(before) hook and pos_validation
with precmd
(after) hook.
autoload -U add-zsh-hook # Load the zsh hook module add-zsh-hook preexec pre_validation # Adds the pre hook add-zsh-hook precmd pos_validation # Adds the pos hook
I'm not planning to remove these hooks, but you can do it with these commands:
# add-zsh-hook -d preexec pre_validation # Remove it for this hook # add-zsh-hook -d precmd pos_validation # Remove it for this hook
Once finish, reopen all terminals or update his source running source ~/.zshrc
command and now you are ready to use validations.
Example
You can download or clone this code and other ZSH utilities from GitHub: dot Files repository.
That’s All Folks!
Happy Coding 🖖
Sources
Top comments (1)
Nice! This inspired me to put the following in my
.zshrc
, for all the times I want to know the contents of a variable or what the result of an expansion would be, and I find it tedious to type echo or I outright forget. Now I don't have to anymore. Similar to theauto_cd
option.Which gives: