How to make `cd dir/filename` take me to dir/?

I assume you still want to retain the original functionality if you input a directory, and you are using bash.

cd() {
    local file="${!#}"

    if (( "$#" )) && ! [[ -d "$file" ]]; then
        builtin cd "${@:1:($#-1)}" "${file%/*}"
    else
        builtin cd "$@"
    fi
}

If you are never going to use cd's options (-P, etc), then this will also suffice:

cd() { 
    if [ -d "$1" ] || [ -z "$1" ]; then
        builtin cd "$@"
    else
        builtin cd "${1%/*}"
    fi
}

You could use dirname to strip the filename from the path, e.g.

mycd() { cd "$(dirname "$1")"; }

See man dirname.


In zsh, I often do:

cd /path/to/somefile(:h)

(h for head).

If somefile is a symlink, you can also do:

cd somefile(:A:h)

To get to the directory where the target of the symlink may be found.


The zsh equivalent of Chris' now bash-only solution would be:

cd() {
  [[ ! -e $argv[-1] ]] || [[ -d $argv[-1] ]] || argv[-1]=${argv[-1]%/*}
  builtin cd "$@"
}

In zsh, you can also redefine what "words" Ctrl-W removes.

In zsh, "words" in the context of the word-based motion/transpose/delete widgets are sequences of alnums plus the characters in the $WORDCHARS variable which by default includes /.

You could remove / from $WORDCHARS so that Ctrl-W only deletes one path component:

WORDCHARS=${WORDCHARS/\/}

Another useful extension is the select-word-style widget which you can use to interactively choose between different word styles.

autoload select-word-style
zle -N select-word-style
bindkey '\ew' select-word-style

Then pressing Alt-W allows you to choose between different word styles.

$ cd /blah/blih<Alt-W>
Word styles (hit return for more detail):
(b)ash (n)ormal (s)hell (w)hitespace (d)efault (q)uit
(B), (N), (S), (W) as above with subword matching
?