Can I hook into the cd command?
Solution 1
You could add this function to your .bashrc
or other startup file (depending on your shell).
cd() {
if [ "$1" = "public_html" ]; then
echo "current dir is my dir"
fi
builtin cd "$1"
}
Solution 2
With ksh
or bash
(or zsh
):
cd() {
builtin cd "$@" || return
[ "$OLDPWD" = "$PWD" ] || case $PWD in
(*/public_html) echo do something
esac
}
With zsh
:
chpwd()
case $PWD in
(*/public_html) echo do something
esac
(chpwd
is a hook function that is called whenever the current working directory changes (by way of cd
, pushd
, popd
...)).
Solution 3
Wrapping cd
, an existing command, is not recommended.
A more universal solution would be defining a custom chpwd
hook in Bash. (According to tags of this question, I assume you're using Bash)
There's not a complete hook system designed in Bash when compared with other modern shells. PROMPT_COMMAND
variable is used as a hook function, which is equivalent to precmd
hook in ZSH, fish_prompt
in Fish. For the time being, ZSH is the only shell I've known that has a chpwd
hook builtin.
PROMPT_COMMAND
If set, the value is interpreted as a command to execute before the printing of each primary prompt ($PS1).
https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Bash-Variables
chpwd
Hook in Bash
A trick is provided to setup a chpwd
equivalent hook in Bash based on PROMPT_COMMAND
.
# create a PROPMT_COMMAND equivalent to store chpwd functions
typeset -g CHPWD_COMMAND=""
_chpwd_hook() {
shopt -s nullglob
local f
# run commands in CHPWD_COMMAND variable on dir change
if [[ "$PREVPWD" != "$PWD" ]]; then
local IFS=$';'
for f in $CHPWD_COMMAND; do
"$f"
done
unset IFS
fi
# refresh last working dir record
export PREVPWD="$PWD"
}
# add `;` after _chpwd_hook if PROMPT_COMMAND is not empty
PROMPT_COMMAND="_chpwd_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}"
Since we're detecting PWD
change directly, the solution works with cd
, pushd
, and popd
.
Note: The main difference between our chpwd
implementaion in Bash and the chpwd
in ZSH is, PROMPT_COMMAND
is not supported in a non-interactive Bash shell.
Usage
_public_html_action() {
if [[ $PWD == */public_html ]]; then
# actions
fi
}
# append the command into CHPWD_COMMAND
CHPWD_COMMAND="${CHPWD_COMMAND:+$CHPWD_COMMAND;}_public_html_action"
Source: Create chpwd Equivalent Hook in Bash from my gist.
For anyone want an answer for ZSH. Use chpwd
hook in ZSH. Don't define chpwd()
function directly. More detail here.
Solution 4
I am not a bash expert but I would take @UVV's answer and modify it just a little so that it does this:
- instead of checking for
public_html
, I'd just check for somehook-script
file in the target dir$1
, say,cd_hook.sh
. - if that
hook-script
exists, run it, and move on with thecd
This seems more generic because you'd then be able to apply the cd
-hook to any directory if you so choose, by just adding a cd_hook.sh
in the said directory.
Related videos on Youtube
TMH
Updated on September 18, 2022Comments
-
TMH over 1 year
I'm trying to set something up on a server I run, when ever I
cd
into apublic_html
folder 95% of the time there's a few commands I will always run to check certain things.Is there anyway I can hook into
cd
so if the directory is apublic_html
, it will automatically run the commands for me?If I can't hook into the
cd
command, are there any other things I could do to achieve the outcome I'm after?I'm running CentOS 5.8.
-
TMH over 9 yearsOoh, this looks interesting. I've added this to my .bash_profile, and added a
echo "Testing..."
just above the if, but nothings output. Do I need do something to apply these changes? -
UVV over 9 years@TomHart If you didn't start a new session then you have to source the file into your current session by
. ~/.bash_profile
-
UVV over 9 years@TomHart it seems there's no
/bin/cd
in my CentOS, so this solution might not going to work -
TMH over 9 yearsI've just noticed that now. I found this question which states why unix.stackexchange.com/questions/116955/where-is-cd-located. Still a good solution for system that actually have a /bin/cd though :).
-
UVV over 9 years@TomHart Actually I fixed the function using your link ;)
-
TMH over 9 yearsThat's teamwork :P. I'll be able to get it working great now. Thanks :).
-
Stéphane Chazelas over 9 yearsDoes not work if you
cd -P public_html
orcd ~/public_html
or has unexpected behaviour if you can'tcd
intopublic_html
. -
Stéphane Chazelas over 9 years
.bash_profile
is for session settings, not for customisingbash
(for which there's~/.bashrc
) -
Stéphane Chazelas over 8 yearsIt seems generic, but you're introducing a security vulnerability. Someone or something only needs to plant a hook-script in /tmp for instance to make you run any code the next time you cd there. You'd want at least to make sure that the hook-script is owned by you, not a symlink, not writable by anyone other than you, that the directory it's in is only writable by you... See Keeping history per working directory (cf. per shell session) for a safer approach.
-
lost-and-found over 8 yearsThanks for the security insight @StéphaneChazelas. I have to admit I didn't even think about it.
-
Duong LV over 5 yearsI found this question while doing just that: if I
cd
somewhere, check for a.bashcd
file and run it if it exists.