cd’s long lost sibling finally here!

Posted by Michał ‘mina86’ Nazarewicz on 2nd of June 2024

cd is a straightforward command. As per the name, it changes the directory and does its job perfectly well. But what if it could do more? One scenario is wanting to execute a command inside a specific location without affecting the current working directory (CWD). This article introduces a cd replacement which offers that feature as well as provides more ways to specify the target directory.

It is important to note that it’s not intended for scripting. Rather, it’s only meant for interactive use where it streamlines some operations.

New Features

For impatient readers, the code is available on GitHub. Otherwise, let’s first go through the new features of this enhanced cd.

  • It takes a command as an optional argument. The command is launched inside of the target directory without changing CWD, for example:

    ~/code/rust-rocksdb/librocksdb-sys$ cd .. cargo build
    # ... builds rust-rocksdb rather than librocksdb-sys
  • The target directory can be specified as a file. The code will change to directory containing that file. This is convenient when copying and pasting paths. A file location can be passed without having to strip the last path component, for example (border around text symbolises copying and pasting):

    ~/code/linux$ git whatchanged -n1 |grep ^:
    :100644 100644 8ddb2219a84b 6b384065c013 M	include/uapi/linux/kd.h
    ~/code/linux$ cd include/uapi/linux/kd.h
  • The target directory can be specified using a path starting with .../. The code navigates up the directory tree until a matching path is found, for example:

    ~/code/linux/drivers/usb/gadget/udc$ cd .../Documentation
  • The enhancement integrates with Bash’s autocd option. With it enabled, invoking a directory followed by a command executes that command inside of said directory, for example:

    /tmp/bash-5.2$ ./examples pwd
    cd -- ./examples/ pwd
  • cd -P resolves all symlinks in PWD. I’ve found this is more useful than POSIX-mandated behaviour. For consistency, of cd -L also doesn’t switch to home directory.


The new cd comes as a shell script which needs to be sourced in ~/.shellrc, ~/.bashrc or equivalent file.

I further recommend adding an alias for - command. This may look strange, but creating a hyphen alias is perfectly fine even though it requires some care. autocd in Bash is also worth a try.

The enhanced cd together with those optional configuration options can be installed by executing the following commands:

mkdir -p ~/.local/opt
cd ~/.local/opt

# Replace with ‘master’ to get the latest version though
# be warned that there are no guarantees of compatibility
# between the versions.
wget "${commit?}/bin/"

if [ -e ~/.local/opt/ ]; then
    . ~/.local/opt/

# Bash interprets ‘-=…’ as a flag so ‘--’ is needed but
# BusyBox complains about it so silence the warning.
alias -- -="cd -" 2>/dev/null

# Add to Bash
echo "${install?}"      >>~/.bashrc
echo "shopt -qs autocd" >>~/.bashrc
# Add to other shells
echo "${install?}"      >>~/.shellrc


Firstly, the enhanced command does not support any other switches shell’s cd might offer such as -e or -@. Anyone who relies on them should be able to add them to the script with relative ease.

Secondly, the command doesn’t fully integrate with CDPATH. While basic functionality of CDPATH works, it cannot be combined with alternative target directory specification used by the new cd.


There are commands a seasoned shell user may use without giving them a second thought. Certainly, cd is so obvious and straightforward that there’s nothing to change about it. However, accepting that even fundamental commands could be changed may lead to improvements in one’s workflow.

I’ve been using various forms of enhanced cd for over a decade. And with this post I hope I’ve inspired you, Dear Reader, to give it a shot as well. The exact set of features may not be to your liking, but nothing stops you from writing your own cd replacement.

Note that the repository includes my dot-files and I may with time update functionality of the script to the point where description in this article is no longer accurate. This post is describing version at commit 8ca6070c. Setup instructions in Installation section are pinned to that version.