Navigating around in your shell
Navigating around in your shell

      

 Nov 16, 2023 . 5 min 



I have been using terminals for a long time, initially because I thought they looked cool, and later because I genuinely found them to be easier/faster to get stuff done. And since I've been at it for a while, navigating through directories is something I think I've gotten good at. In this blog, I would like to give some tips on ways you can navigate around in your shell quickly.
I rarely type cd to change directories. I get the same feeling you get when you see people google for google on google when I see people typing cd .. repeatedly.
Basics #
Using cd #
We all know the basics, ie cd <dir> to navigate to dir.
Here a few other things ways you can use cd:

cd (no args) is equivalent to cd ~
cd - takes you to the previous(not parent) directory
cd .. takes you to the parent directory

Make use of that tab key #
This might sound simple, but you have no idea how many times I've had the painful experience of watching people type out the path by had and even end typing them incorrectly.
Let's add some useful aliases #
Now that we know some basics, lets add some aliases.
Here are the ones I really like. I would suggest adding aliases for going to previous dir, and multiple levels of parent dirs. I initial got this idea from ohmyzsh/ohmyzsh. You can find these in my dotfiles.
alias -- -='cd -'alias ..='cd ..'alias ...='cd ../..'alias ....='cd ../../..'alias .....='cd ../../../..'alias ......='cd ../../../../..'
Make use of globs #
If you know only parts of a path, you can always use globs and let shell figure out the exact path. Use this along with tab completion to make it even more powerful.
For example you can do cd src/**/color to find a directory named color in the current working directory.
Builtins #
Auto fix small errors #
Since my blog is mostly read by humans(I'm sorry bots, you are in a minority), and since humans make mistakes, this one is for you. I would suggest enabling these two options. The first one ignores the case of the argument and the second one auto fixes any small spelling mistakes.
# for bashshopt nocaseglob # ignore case when matchingshopt cdspell # fix common spelling mistakes# for zshsetopt nocaseglob # ignore casesetopt correct # correct spelling mistakes
You might be interested in shopt and setopt manuals.
For the lazy ones #
Why type cd if you don't have to. If you enable to following option, you can just type the name of the folder and if there is no binary by that name in your $PATH, your shell will cd into it that directory.
shopt -s autocd # for bashsetopt auto_cd # for zsh
Remembering a directory #
What if you wanna move around a lot, but wanIf you're frequently on the move but need to stay organized and revisit specific directories easily, utilizing pushd and popd can be incredibly beneficial.t to keep track of certain directories specifically to come back to. pushd and popd are you friends.
pushd dir1 # in dir1cd dir2 # in dir2pushd dir3 # in dir3cd dir4cd dir5popd # in dir3popd # in dir1
Bookmarks #
hash is a way for you to "bookmark" directories. I use it to "bookmark" directories that I visit often. By default, the bookmarks are only per session, but you can add a bit more code to make it persistent.
The best part is that you can use these as prefixes to construct the full paths. For example if I have bookmark ~/.local/share as ~share, I can later do things like cd ~share/emacs.
Here are the additions that I have:
[ -f "$HOME/.local/share/.zsh_dir_hashes" ] && "$HOME/.local/share/.zsh_dir_hashes"hashdir() {    [ -z "$1" ] && echo "Pass hash to use for dir" && return 1    hash -d "$1"="$(pwd)"    echo hash -d "$1"=\""$(pwd)"\" >>"$HOME/.local/share/.zsh_dir_hashes"}
Use CDPATH env variable #
You can set this env variable with the paths that you would like to always cd into.
For instance, if I set it as export CDPATH=$HOME/.config:$HOME/.local/share, I can cd into any dirs in $HOME/.config and $HOME/.local/share form any location. Moreover, these paths will be incorporated into your shell completions.
Scripts and aliases #
Make a directory and cd into it #
I more of than not find myself having to create a directory and cd into it. I use an function called take for this. This is another one of those gems I stole from oh-my-zsh.
take () {    mkdir -p "$1" && cd "$1"}
Navigating to project root #
Another common usecase is to go the root of the project. Let's also simplify it by using git to figure out the root of the project.
r () {    cd "$(git rev-parse --show-toplevel 2>/dev/null)"}
Navigate to a project under this dir #
Like most people, I too maintain a dir under which I keep all my project. This function lets me pick one of those projects (using fzf to filter). It looks for all dirs with a .git in them and find their parent dirs.
jj () {    cd "${1:-.}/$(find . -maxdepth 5 -type d -name .git | sed 's|/.git$||' | fzf --preview 'tree -L 2 ./{}')"}
Quickly create a tmp dir #
Whenever I want to test out something, or look at(clone) a project just temporarily, I used to create a dir under /tmp and then do it there. This script automates that. The actual script that I use also does a git init so that I can track and diff files.
tmp () {    [ "$1" = "view" ] && cd /tmp/workspaces && cd $(ls -t | fzf --preview 'ls -A {}') && return 0    r="/tmp/workspaces/$(xxd -l3 -ps /dev/urandom)"    mkdir -p -p "$r" && pushd "$r"}
One-off dirs #
One more. I get a lot of data being sent to be as zips, and when I want to look at them, just like before, I create a dir in tmp, unzip it into that dir and look into the logs. After a while I automated these steps. This can sound like a me problem, but just wanted to show you the kind of things you can do.
,showme () {    [ -z "$1" ] && echo "Pass file to show" && return 1    tmp="$(mktemp -d)"    unzip "$1" -d "$tmp"    cd "$tmp" || return 1    clear && echo && echo "$1" && lsd}

fzf #
fzf is a super versatile tool. I use it a lot in scripts, but by default it adds a ctrl+t shortcut to select files and folders.
Intelligent cd #
There's a multitude of tools available that learn the directories you frequently access and allow you to swiftly "jump" into them by typing partial names. I personally rely on rupa/z due to my familiarity with it, but there are several other options worth exploring, such as wting/autojump, ajeetdsouza/zoxide (the Rust one for extra credibility), and gsamokovarov/jump. Each offers its own set of features and advantages, catering to different preferences and workflows.
Using a TUI file browser #
I grew up using ranger/ranger but switched over to gokcehan/lf at some point and I use it as way to select the dir that I wanna jump into. The following code is taken straight from lf's wiki. With this, you can type lfcd, then go to the dir you want by navigating a TUI browser and then exit to land on that dir.
lfcd() {    dir=$(lf -print-last-dir "$@")    while ! cd "$dir" 2> /dev/null    do        dir=$(dirname "$dir")    done}
Fuzzy tui navigation #
Another option is to use something like Canop/broot to select a dir. I don't use this much, but have found this useful in the past. You can find how to do that here.
Bonus #
I always wondered if cd . had a purpose. I found this out from someone on Mastodon a while ago (unfortunately, I don't remember who).
If you delete a folder from a different terminal session and subsequently recreate a new folder with the same name, using cd . allows you to navigate into the newly created folder without changing your current directory. This command essentially refreshes the current directory, enabling access to the newly created directory with the same name.


← Home

    