13

I'm trying to set something up on a server I run, when ever I cd into a public_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 a public_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
  • 427

5 Answers5

18

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...)).

15

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"
}
Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
UVV
  • 3,068
  • Ooh, 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? – TMH Nov 27 '14 at 13:19
  • @TomHart If you didn't start a new session then you have to source the file into your current session by . ~/.bash_profile – UVV Nov 27 '14 at 13:20
  • @TomHart it seems there's no /bin/cd in my CentOS, so this solution might not going to work – UVV Nov 27 '14 at 13:32
  • I've just noticed that now. I found this question which states why http://unix.stackexchange.com/questions/116955/where-is-cd-located. Still a good solution for system that actually have a /bin/cd though :). – TMH Nov 27 '14 at 13:33
  • @TomHart Actually I fixed the function using your link ;) – UVV Nov 27 '14 at 13:37
  • That's teamwork :P. I'll be able to get it working great now. Thanks :). – TMH Nov 27 '14 at 13:39
  • 1
    Does not work if you cd -P public_html or cd ~/public_html or has unexpected behaviour if you can't cd into public_html. – Stéphane Chazelas Nov 27 '14 at 16:01
  • .bash_profile is for session settings, not for customising bash (for which there's ~/.bashrc) – Stéphane Chazelas Nov 27 '14 at 16:04
9

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.

Simba
  • 1,682
1

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 some hook-script file in the target dir $1, say, cd_hook.sh.
  • if that hook-script exists, run it, and move on with the cd

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.

0

Using powerful zsh approach in bash:

First an easy way to extend bash:

~/.runscripts

#load all scripts inside $1 dir

run_scripts()
{
    for script in $1/*; do

        # skip non-executable snippets
        [ -f "$script" ] && [ -x "$script" ] || continue

        # execute $script in the context of the current shell
        . $script
    done
}

Include in to .bashrc:

. ~/.run_scripts

run_scripts ~/.bashrc.d

You can create ~/.bashrc.d/cdhook with:

#!/bin/bash

chpwd() {
  : #no action
}

cd() {      
   builtin cd $1
   chpwd $1
}

Now is up to you to replace the function:

#list files after cd
chpwd() {
  ls -lah --color
}
albfan
  • 231