Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login
Behold z, the unsung jewel that rethinks shell navigation (aymericbeaumet.com) similar stories update story
142.0 points by aymericbeaumet | karma 156 | avg karma 11.14 2021-02-16 12:54:43+00:00 | hide | past | favorite | 71 comments



view as:

z and fzf are among the first things i install on a new account.

A similar tool that saves me immeasurable amounts of time is fasd[0]. I started using it as a part of prezto[1], which is similar to oh-my-zsh, and have never gotten around to trying any other solutions such as z.

[0] https://github.com/clvv/fasd [1] https://github.com/sorin-ionescu/prezto



This sounds just like autojump (typically run using `j`) to me: https://github.com/wting/autojump

Agree that it's an invaluable piece of software!


Any idea what the differences are? Am I missing anything by keeping to use autojump?

No, it seems from the article it's a clone.

Seems like autojump used to work with regexps but now it's something custom. Z works with regexps.

funfact: vim does this with **, and tab-complete.

For navigating between parallel directory structures (src/ and test/), I made an awful hack called c-, that sed subs src/ for test/ and vice versa on pwd. A fluke grade.


When actually inside vim Tim Pope's excellent vim-projectionist has a wonderfully useful feature for flipping between various related files(:h projectionist-alternate). The whole plugin is really cool, it makes it so simple to configure project specific working environments with it.

https://github.com/tpope/vim-projectionist


I am now using https://github.com/ajeetdsouza/zoxide (in Rust) and it works really well.

I use zoxide - a modern z written in Rust.

https://github.com/ajeetdsouza/zoxide


z.sh is a 243-line shell script. What makes this Rust version better or more modern?

given that zoxide is not bash, it works in other shells like fish

I don't know about fish, but z does work in zsh at least.

As of about 5 minutes after reading that, so am I. Thanks!

I use https://github.com/clvv/fasd which has all the functionality of z but with some other goodies as well.

Is there some functionality that `z` offers that fzf doesn't? I have a keybinding that essentially does `open $(fd | fzf)`, and that is how I go _anywhere_ in my file system. Completely changed how I use the shell.

I personally find that fzf is better because I can see where I'm going to end up before I accept the operation.


Besides z being much faster (looking through a sorted list of directories visited instead of recursively walking from the current directory) your snippet looks from the cwd

This is a fair point. I usually only "jump" from directories that have at most 500k files, and the median is way closer to ~500 files.

Even in the worst cases, at least with my i7 NUC and using fd instead of find, it's less than 500ms to load the entire list into fzf.


Yep, that's fair. I use fzf along with z. I use z usually to switch projects (and I work in Go, so many are in GOPATH and annoying to CD to manually) but I use fzf both inside and outside of vim to open individual files.

    I personally find that fzf is better because I can 
    see where I'm going to end up before I accept the
    operation. 
I agree that's a must-have feature. Luckily z does it as well.

Type `z foo` and hit tab.

If there's a single match, "foo" will be expanded in place to the proper path.

If there are multiple matches, you can choose from a list of paths.

So, no mystery navigation (unless you want it) -- you can always see where you're going.


With Bash I use "pushd .", "dirs" and "pushd +1"/"pushd -1".

I guess that's not quite as advanced as z or fasd though!


Not for you, but perhaps for others who also like that behaviour.

With zsh you can enable the auto_pushd option, which makes cd manipulate the directory stack itself. You could probably simply alias cd as pushd too under zsh too, but in bash that would break cd's argument handling.


cd is yahoo circa 1999 (hierarchical organization of information)

z is Google (just give me what I want based on a short description of its name).

z is amazing.


I'm mildly skeptical of any shortcuts that are based on "learning habits". I've already gotten enough of user interfaces that move items based on use all the time (The spotify playlist list is the worst offender - playlists move up and down in rank after every use, so there is never any spatial memory, startled every time).

It's very well hidden, but (at least on Android) there is an option to sort alphabetically. I was quite annoyed until I googled it and found out how to do it. I can't find it in the UI now despite having done it before... Anyway, I fully agree.

You press z, type a few letters and then hit tab until you get the thing you want. It's not spatial. If you use ctrl-r frequently it's similar.

Is there any advantage over CTRL-R?

With ctrl-R you'd presumably need a bunch of absolute path navigation commands in the past, with z you don't need to worry about that.

There may be more clashes, like picking up on filenames instead of directories.

Typing `z res` or whatever is also a bit faster than hitting ctrl-R then `res`.


The examples show "z someinput" and enter, so then going to some place based on learned location for someinput, no?

It's not spatial because it's text-based but a similar problem occurs if it can surprise you about which location is going to be used for each input.


I found the per-directory "suggest-while-typing" history in Fish (and Zsh with the right extension) very intuitive. It speeds up getting around the filesystem, and to common locations tremendously, and of course also remembers regular commands. And it "just works", there is nothing to setup and no commands to remember.

tried fish for some time for the implicit completion but the otherwise excotic nature of the shell has caused me enough headaces to revert to bash and live with C-R

I use zsh with this plugin: https://github.com/zsh-users/zsh-autosuggestions

Best of both worlds, fish-like autocomplete combined with bash-compatibility :)


Tools like this always make me faintly uncomfortable. The idea is nice, but as a systems guy I would liken it to a mechanic’s toolbox that tries to predict what tool you want and puts it in your hand. Seems like it would be nice except you would need to carefully check what tool you were given to make sure the algo didn’t make a wrong decision and you’re using a wrong-sized wrench or something.

I’m not sure I want the fundamental building blocks of my field to be “helpful” like this. I’m much more a fan of naming it easier and faster for computers to do what I want, than I am of computers trying to divine what I want without my explicitly asking for it at this level.


It sounds terrific. Also make sure to check out the fish shell if you haven't before. It's tab completions/up-arrow completions including for cd are really useful in a similar way.

I’ve used fish for quite a while but after Many a scripting incompatibility I went back to ohmyzsh. Fish is great if you can port your whole ecosystem into it.

I find the persistent directory stack of ohmyzsh (easy enough to enable yourself in zsh) easier to use than things like autojump or z, and pretty much makes them unnecessary. I miss this basic functionality in fish (hoping someone will point out that I have overlooked it)

Care to elaborate? Nowadays i usually use history with fzf to find old cd commands.

cd - <tab> to view numbered list of previous directories. hit the number to cd there

Thanks! I'll need to train myself to use this, it's super cool to learn a new trick like that.

If you just type cd space and hit the up arrow X times.. normally it give a good guess without having to do that just after entering cd space.

don't forget about CDPATH

  $ export CDPATH=~/Workspace/src/github.com # in .bashrc
  $ cd brigad/ops

In my experience, CDPATH is a great way to lose hours chasing down errors throughout your scripts.

"CDPATH=<str>" without the export will work as you'd want, and won't pollute the environment for subshells and scripts. It is unlikely you really want to export anything listed in the shell variables section of the man page, but yeah everybody does :/

[This message brought to you by https://news.ycombinator.com/item?id=22978770]


TIL, thanks :)

I use 'cz' which is like 'cd' but for git workspaces only. Uses fzf to present list of matches.

bash source:

cz-index () { sudo find -L ~/work -type d -name '.git' | sed 's;/.git$;;' | sort > ~/git-dirs.txt }

cz () { cd "$(cat ~/git-dirs.txt | fzf --tiebreak=begin --exact -i -q $1)" }


I develop apps on Windows, but I use Linux to do lots of my work and automate cumbersome boring tasks where I can (there are still many more to be automated....).

I'm constantly amazed at what Windows dev people can get done without a programmable command line. I've seen several thousand line long cmd/bat files to do relatively simple things. They work, which is good. They are a lot of work to maintain though.

I find z absolutely wonderful to take away that first hurdle of remembering folders. I can't imagine how Windows devs who don't know Unix can get around easily. They seem to though. Much must be memorised and some tools help. Powershell is getting better, but I think lacks (at least for the moment) the amount of existing code/books/links that shell solutions have.

I sometimes hum my version of that old Sting favourite,

   Oh, I'm an alien, I'm a legal alien
   I'm a Linux dev in Windows 10....
I'd be interested to hear if there are better/equivalent searching tools easily available on Windows, but z works wonderfully for me.

Windows doesn't lack a programmable command line. If the Windows devs around you are writing bat files, they need to be introduced to PowerShell.

Powershell always felt more like a .net REPL than a normal shell to me.

> I can't imagine how Windows devs who don't know Unix can get around easily. They seem to though.

It's simple, for filesystem operations most Windows people don't use CLI. I use Total Commander for example, which has tabs and bookmarks to quickly navigate around the filesystem.


For shell scripts that are longer then a handful lines, python is the better alternative IMHO, especially if the scripts need to work across Windows, Linux and macOS.

Windows has some nice tricks to connect the UI to the cmdline. For instance you can type "cmd" or "powershell" in the breadcrumbs-bar of an Explorer window, and it opens a terminal at that filesystem location (and the other way around, "start ." on the command line opens an Explorer window in the current directory.

Historically, pure command line workflows are somewhat rare on Windows though.


Windows devs should be using powershell not bash.

Stopping at "a Linux dev" would still be meaningful. Coz we are (aliens), in the quantitative sense.

Ugh. Powershell takes several seconds to load. Sometimes 5 to 10 seconds to load, which is forever, if you just want to run a simple command.

Or use Elvish, which has builtin directory history :)

Directory history is the 3rd demo on the homepage: https://elv.sh/


z is amazing. z and fish shell are the two biggest shell productivity boosters I've ever used.

How do you install z on fish? z.sh is supposed to be sourced, but that won't work in config.fish.

Other than the already mentioned zoxide, there's also https://github.com/jethrokuan/z

Oh-my-zsh with the fzf plugin has a lot of navigation-friction removal.

    cd ~/r/pr/e/de<tab>
Becomes

    cd ~/repos/projectlongname/environments/development
It also has built in push/pop, with minus always returning to the previous path, various numbers of dots, up to six I believe, navigating up the tree, and cd - <tab x2> showing interactive breadcrumbs of recent paths for easy as click-and-click navigation.

I think most of this is out of the box OMZ (without the fzf plugin).

Built-in zsh behaviour in fact, oh-my-zsh just enables some extremely useful non-default options.

With a compinit call the directory substring expansion will work. And, with auto_pushd enabled cd fiddles with the directory stack.

The ....... behaviour is interesting because it uses a global alias(alias -g) which is an awesome feature for text expansion anywhere in a line, unlike standard aliases which only expand where commands should be given. It means, for example, you can do `readlink -f ......` and it would perform `readlink ../../../../../..`. Aliases on zsh are very powerful indeed.

I'm writing this text in the hope it drives at least one person to burn an afternoon on the amazing(but huge) zsh documentation, because the entire thing is full of gems.


I'll add that to my Read-Only Friday. I got tossed directly into the zsh/omz/fzf pool head-first from bash, so the borders of what's what are murky. Definitely some powerful stuff, so far.

In which case, I've won!

Seriously though, I think you were probably lucky to have experienced zsh that way. The out of the box experience is incredibly bare. Said as a fellow oh-my-zsh user going back the full twelve years, according to the history of oh-my-zsh's jnrowe theme ;)

I do believe there is a lot of useful knowledge to be gained from working back towards zsh first principles though, especially if -- like me -- you spend hours a day alongside the prompt.


I can't imagine moving around without z, the biggest pain with my CLI use is when z isn't working properly and I have to revert to cd-in around ....

Nice. I made a similar tool that saves and searches the history by a query string. In order to keep the history separate for each session I save it to a different file. Nothing I type is ever lost, I can always search for it.

I have been using `z` for some time, and now I can't imagine working without it.

I used to have a big list of aliases like:

  alias pro='cd ~/Projects'
Seems trivial, but it was a huge time saver over time. After installing `z` and using it for a few days, I can now keep only the top 3/4 aliases and `z` does the rest.

I've been tempted to try more fancy tools like zoxide, but I love the fact that `z` is just a shell script I can easily move around.


OP here, thanks for the amazing comments. Some nice projects to look into!

As much as I love z, I'm also a fan of fzf, both are really complementary. I'm using this little piece of code (not from me, but cannot find the original source) to fallback to fuzzy search when z fails to find a result or when no args are given:

  unalias z &> /dev/null
  z() {
    [ $# -gt 0 ] && _z "$*" && return
    cd "$(_z -l 2>&1 | fzf --nth 2.. +s --tac --query "${*##-* }" | sed 's/^[0-9,.]* *//')" || exit 1
  }
I also use this approach in a few other places in my workflow (git checkout, vim, etc). Expect a blog post covering this in the near future.

why would anyone sing a jewel anyway

Native zsh version: https://github.com/agkozak/zsh-z

(No external tools, so no forking of awk, sort, date, sed, mv, rm, and chown. Plus some stability improvements in terms of race conditions...)


Legal | privacy