Settings

Theme

Don't waste your time by cd-ing in the terminal

huyng.com

449 points by siim 15 years ago · 123 comments

Reader

mtrn 15 years ago

Don't waste your time bookmarking directories, jump right to them ;) https://github.com/rupa/z

`z` tracks your most used directories. After a short learning phase, it will take you to the directory, based on its usage frequency and a hint you give it on the command line. Say I am often cd'ing into /var/www - then after a while I can just type `z ww`.

  • SwellJoe 15 years ago

    I love projects like this. They so elegantly show what using the right tool for the job can do for you, in terms of code simplicity and conciseness. Doing this in, say, Perl or Python or Ruby, would be entirely possible, and folks who code exclusively in those languages might assume it would be easier in a "more powerful" language...but Bash has so many nice little built-ins that make it really concise and portable. One file, no modules, and it does exactly what it's supposed to do.

    I think it's illustrative that the developer went through a Python-based version on the path to building z.

  • webXL 15 years ago

    I want to be able to preview the path or directory name that z will navigate to. Something like the way the webkit developer console autocompletes an object, method, or property in light gray color. Or it could be displayed in the terminal title bar. Is that possible?

  • stevelosh 15 years ago

    z is great. I don't know how I lived without it.

    It's become so ingrained in my fingers that whenever I switch to a new shell it's the first thing I port over:

    https://github.com/sjl/z-zsh

    https://github.com/sjl/z-fish

  • dekz 15 years ago

    I remember seeing this, but forgot entirely to use it. Have been spending a while looking for it again, or something equivalent. Thanks.

    • mtrn 15 years ago

      I forgot the url, too. But then I remembered the tagline "z is the new j" - which is enough for google to bring up the repo - even without quotes.

  • orlandu63 15 years ago

    I've created an AUR package for this script, found here: http://aur.archlinux.org/packages.php?ID=46675

    • mtrn 15 years ago

      Out of the box only with `z -l foo` # list all dirs matching foo (by frequency)

alanh 15 years ago

I like this workflow better:

1. Go to the directory in question

2. Type "save nm" where "nm" is any short name for the directory, like "blog" or "blg"

3. From now on, type "cd nm" whenever you want to go there.

No session restart required, even.

I copied the code that enables this workflow from http://dotfiles.org/~jacqui/.bashrc (or was it https://gist.github.com/117528)

The idea is discussed here: http://hints.macworld.com/article.php?story=2002071600512379...

  • sjs 15 years ago

    Or in zsh:

        setopt cdablevars
        nm=/path/to/whatever
        cd nm
    • irfn 15 years ago

      you can put this in ~/.zshrc for persistent zsh bookmarks

        touch ~/.zshmarks && source ~/.zshmarks
        function b() {
          echo "hash -d $1=\"`pwd`\"" >> ~/.zshmarks && source ~/.zshmarks
        }
    • unfletch 15 years ago

      in Bash, change the first line to:

          shopt -s cdable_vars
      • _b8r0 15 years ago

        in Bash you don't even need to do that, just do:

            foo=/etc/
            cd $foo
  • hyperbovine 15 years ago

    Dollars to donuts the author is a Vimmer. I am and the workflow makes complete sense to me :-)

  • anon_d 15 years ago

    Why not just:

        echo "export nm=`pwd`/blog"' >> ~/.profile
        . ~/.profile
        cd $nm
    
    There's no need for magic when you know how to shell.
    • fabjan 15 years ago

      Why not just

          shopt -s cdable_vars
          nm=`pwd`/blog
          cd nm
      
      No need for hacks when you know how to shell.
      • anon_d 15 years ago

        Annoying special cases:

            $ cd /
            $ nm=/foo
            $ ls | grep nm
            $ cd nm
            $ pwd
            /foo
            $ cd ~
            $ ls | grep nm
            nm
            $ cd nm
            $ pwd
            ~/nm
            $ echo FFFFFUUUUUUUUU
        
        Inflexible:

            $ cd nm/jan/img
            cd: No such director nm/jan/img
            $ echo SHIT
            SHIT
            $ cd $nm/jan/img
        
        Worse, It's nonstandard and only saves you one chracter.
huyegn 15 years ago

Hey Guys,

This is my blog.

FWIW, I've actually switched away from using the script mentioned in the link posted by OP and have moved towards using an improved version below.

http://www.huyng.com/bashmarks-directory-bookmarks-for-the-s...

This new version has 3 commands:

    - "s" for save current directory as a bookmark
    - "g" for jump to bookmark's directory
    - "l" for list all bookmarks.
philikon 15 years ago

I first was excited by title "Don't waste your time by cd-ing in the terminal", but then it just turned out to be a blog post about making cd'ing quicker. If you want to boost your productivity, my advice is to stop cd'ing altogether.

I see a lot of people -- particularly vi users -- cd'ing back and forth through a large directory tree. I usually tell them to get a terminal emulator that lets you easily manage many terminals open. Open one per directory you want to operate in, for instance. Learn how to switch back and forth between the different shells.

But most importantly, don't quit the program to switch back and forth between directories and files. Learn to use your editor of choice properly: how to view directory listings, how to switch back and forth, etc. Vim can do this just fine btw. The choice of tool here doesn't matter so much. Just pick one and learn it. This applies to your choice of terminal emulator, shell, editor, etc.

  • moe 15 years ago

    Open one per directory you want to operate in, for instance.

    This is a common source of headache when using the terminal as an IDE. Not only is it easy to get lost in a sea of terminal-tabs, but it's also quite cumbersome to restore the state of 5+ tabs after a shutdown or disconnect. Even more so when GNU screen enters the mix.

    What I'd really like to have is a terminal that can attach to a remote GNU screen and display the screen-windows as local tabs.

    • peterwwillis 15 years ago

      So browsing graphical tabs is quicker for you then using "Ctrl+RightArrow" or "Ctrl+n" or some variation of one of those? Traversing my screen or tmux sessions is usually much faster than using a mouse.

      • moe 15 years ago

        Traversing is not the issue here, it's more about having an ad-hoc way to watch things side-by-side by dragging a tab to a window and vice versa, and about having a proper scrollback.

        Yes, screen, tmux and vim have split window modes, but those are cumbersome to operate (and I'm saying that as a year-long ion3 user) and the scrollback issue has not been addressed by either up to this day.

        Or, to put it more generally: Terminals are sadly stuck firmly in the 1970s. There has been near zero innovation beyond emulating them in tabbed windows and setting xterm titles. Heck, we're moving backwards. OSX ships with a terminal that doesn't even support 256 colors. ZModem is unheard of except in fairly exotic/old emulators such as Zoc. Support for "advanced" terminal features (double-size fonts, graphics mode) is rare.

        I spend >8hrs/day inside a terminal. I would happily pay a 3 digit license fee for a modern terminal emulator that adds the features I mentioned and innovates beyond. There's infinite room for innovation by leveraging special ESC-sequences (server tells terminal what to do), drag & drop, integrating with tools like screen, ssh or even building new CLI tools that interface with the terminal in a smart way...

        I want vim to tell my terminal to display NerdTree in a native side-car widget like TextMate. I want an "open" CLI-command that downloads the target-file from the remote server and displays it locally without me having to futz with scp. I want to drag & drop files onto the server that I'm currently ssh'd into. I want the term to maintain my entire session (including all tabs and remote connections) across reboots. And, yes, I'd like to have my remote screen windows line up neatly as native tabs.

        • lukeschlather 15 years ago

          >I want an "open" CLI-command that downloads the target-file from the remote server and displays it locally without me having to futz with scp. I want to drag & drop files onto the server that I'm currently ssh'd into.

          You can get this by editing files over sshfs.

          In general though, I find that sort of persistence to be somewhat unstable. I'd rather know that everything I have done is documented and backed up than just sitting in some sort of dump of memory.

          • moe 15 years ago

            You can get this by editing files over sshfs.

            Been there, it's a kludge and tends to not cope well with network disconnects. Also when sshfs flakes out then it has a habit of leaving you with 0-byte files.

            Also note this doesn't fully address the problem. I literally want to drag/drop into the current directory of whatever server I'm ssh'd into (possibly with multiple ssh-hops in between).

            This has been possible in the 80's, it's called ZModem. The server-side part is still in your favorite linux distribution (lrzsz). Sadly the client-side support has disappeared from almost all terminal emulators (Afaik only Zoc still supports it).

            With Zoc you can just drop a file and it will send the ZModem init-string, which conveniently launches the 'rz' binary on the server. Likewise you can say 'sz file', Zoc will detect the init-string and open a download-dialog.

            Forgotten technologies... not all of them were bad.

            • tlack 15 years ago

              I've also been frustrated by these issues. I want to be able to edit a file with local typing speed (i.e., gvim on Windows), but then be able to hit a key and be in a terminal window on that server in that folder to perhaps do a manual grep or rebuild an index or whatever. I feel like we were closer in the 90s with innovative products like Slirp and Term and, yes, Zmodem (and Kermit).

              I started trying to build out something like this based on vim's netrw stuff but it never really worked out. I'm not even sure if what I want is part of vim or if it's some nebulous other tool.

              • __david__ 15 years ago

                Sounds like you want Emacs' tramp. On your local emacs, open a file in the form "/user@remote-ssh-host:file" and it will grab the remote file and edit it locally. Crazily all the emacs version control commands and stuff like M-x compile and M-x grep all work in the remote context. Very cool stuff.

                Obviously this requires that you use Emacs instead of Vim though. Don't be afraid though, the grass is pretty green over here :-).

                • moe 15 years ago

                  No need to switch to an inferior editor. ;-)

                  Vim has this functionality built right in: http://vimdoc.sourceforge.net/htmldoc/pi_netrw.html#netrw

                  However, as said above, for me Tramp/netrw are kludges that tend to add more problems than they solve. A real solution can't be constrained to a particular editor.

                • lukeschlather 15 years ago

                  In my experience, tramp was even more reliable than sshfs. Both need work before they are truly effective solutions.

                  Though the latency of my satellite connection outweighs the shortcomings of sshfs. The thing about tramp is that where sshfs hangs up directory listing and file loading, tramp regularly hangs up the editor. (And tramp should really turn off autosave by default.)

  • erikrose 15 years ago

    Also, pushd and popd. And "cd -". And ctrl-Z and fg to jump out of your editor for a moment. And dragging dirs from the Finder (or whatever) to the terminal.

  • holygoat 15 years ago

    And use tools that are aware of directories: tar -C, NERDtree for Vim, zsh globbing.

  • thet 15 years ago

    a terminal emulator which has a session sasving feature built in to restore terminal tabs with their working directories is: termit find it on github. lua scripting api included :)

cldwalker 15 years ago

Why is a home-rolled cd script interesting when there are many more mature, feature-rich cd-tools out there?

* http://www.skamphausen.de/cgi-bin/ska/CDargs

* http://micans.org/apparix/

* http://github.com/joelthelion/autojump

* http://github.com/rupa/z

* http://github.com/flavio/jump

Also, the title is misleading. I thought it was actually a commandline tool that removed the need to cd most of the time, like lightning: http://tagaholic.me/2010/04/08/lightning-speed-for-your-shel...

  • medwezys 15 years ago

    Ditto, this one feels like reinventing the wheel when we have the tools you named.

julian37 15 years ago

Yet another time saver: if you need to execute only a single command in another directory, use:

  (cd /path; command)
This will cd to /path, run command, but return you to your original working directory. This works because the parens create a sub-process, and the cd command only affects that sub-process.
  • semanticist 15 years ago

    I prefer (cd /path && command), since that way if the cd fails for some reason (like you've typo'd the path), it won't still attempt to run the command.

    • julian37 15 years ago

      Of course! I actually do always use double-ampersand for chaining commands in bash, not sure what made me use a semicolon in that example. Thanks for the correction, a small but important distinction.

  • technomancy 15 years ago

    Appending ";cd -" on the end will have the same effect.

substack 15 years ago

There's also the pushd and popd commands which are part of bash already.

And there's a wikipedia entry for this even: http://en.wikipedia.org/wiki/Pushd_and_popd

  • miratrix 15 years ago

    You can also use the "dirs" command (I think part of bash as well) that tells you the state of the stack. If you set the -v option, you can get the depth of different directories, and you can just do pushd +N to jump to the specific directory.

bretthopper 15 years ago

No mention of ZSH directory stacks yet? http://www.acm.uiuc.edu/workshops/zsh/dir_stack.html

Some helpful aliases to manage them:

alias 1='cd -1'

alias 2='cd -2'

alias 3='cd -3'

alias 4='cd -4'

alias 5='cd -5'

alias 6='cd -6'

alias 7='cd -7'

alias d='dirs -v'

alias h='history'

alias j='jobs'

Just one of the many reasons to use ZSH.

kevinburke 15 years ago

Try autojump, I love it - https://github.com/joelthelion/autojump/wiki

  • dlwh 15 years ago

    Just to help sell it some more: autojump basically watches where you cd and builds a model (of some sort) that guesses where you want to go based on a few characters.

    For instance, I have a project called "structured-prediction" deep in some folder hierarchy, and I can just type "j stru" or "j pred" or even "j uct" and it goes to the directory.

    The best part is that it figures this out automatically. You don't have to remember to bookmark anything.

  • lars512 15 years ago

    Agreed, autojump seems far more principled too than the method described in OP.

  • askedrelic 15 years ago

    Autojump is my vote as well

  • jongraehl 15 years ago

    I also prefer autojump.

aheilbut 15 years ago

I've also wondered to myself why there isn't a terminal program with a directory tree by the side so you could just click on the directory that you want to be in, instead of ls -cd-tab-blah-^H-tab-^M. It would also a have a list of favorite and most-recently-used directories.

A weekend project, perhaps...

xd 15 years ago

Maybe not as quick .. but `ctrl+r cd` gets me there quick enough and I don't have to remember what numeric shortcut is assigned to which directory.

Will give it a shot however, good effort.

gnubardt 15 years ago

Another time saver is to have a function that calls ls after cd'ing:

  c(){ cd "$@" && ls;}
This has probably saved me days over the years, as I almost always want to list a directory after I change into.
  • l0nwlf 15 years ago

    Silly me. I almost always do the same, but never thought of creating a function. Thanks anyways. :D

telemachos 15 years ago

Another built-in worth knowing about is CDPATH.[1] I find that setting a sane CDPATH and bash-completion makes cd-ing anywhere I go regularly pretty trivial - just a few letters and a few TABs and I'm good to go.

[1] http://caliban.org/bash/#bashtips

  • moe 15 years ago

    I'd be extremely careful with CDPATH, never use this on an important host.

    Having "cd foo" potentially take you to an entirely different location can be dangerous, to say the least.

    • telemachos 15 years ago

      I'm not sure I follow. There's nothing dangerous about cd-ing to a directory, though of course it could be dangerous to start work in 'foo', thinking it was 'bar'. Most people use a prompt, or the title bar of their shell to protect against that. But either way, I'm not sure how CDPATH makes that danger greater than any other trick that allows you to jump quickly to a directory using a bookmark, popd or the like.

      • moe 15 years ago

          cd foo
          rm -f *
        
        Removing predictability from the 'cd' command is not a good idea. If you want a smart 'cd' then just call it 'j' or something else. Easier to type, too.
        • telemachos 15 years ago

          Certainly a possible scenario, but anyone who cds into any directory (by whatever means) and enters 'rm -f *' without first checking contents deserves what they get.

          • moe 15 years ago

            Well, this was just the most graphic example, there are more subtle ways to create a mess. Directory names are far from unique, a misfiring 'cd tmp' or 'cd src' can easily lead to nasty surprises, even without 'rm' ever getting involved at all.

            And you do know that CDPATH also affects shell scripts, right?

            • telemachos 15 years ago

              > Directory names are far from unique, a misfiring 'cd tmp' or 'cd src' can easily lead to nasty surprises, even without 'rm' ever getting involved at all.

              I hear what you're saying, though I'm not really persuaded by this argument. When you 'cd' into a directory along your CDPATH, Bash will print out where you end up when you arrive. Here's an example of what I mean (easier to see than explain):

                  circe ~ ❯❯ cd bin
                  circe bin ❯❯ cd ithaca
                  /Users/circe/code/ithaca
                  circe ithaca [master•] ❯❯ 
              
              The regular cd simply takes me where I asked. When I cd and use CDPATH (in the second case), I get told where I end up. Sure, there might be four or five different 'ithaca' folders on various machines and even on one machine, but I think that extra print-out really makes it unlikely that I will get confused.

              > And you do know that CDPATH also affects shell scripts, right?

              No, I'm embarrassed to say, I never thought of this. And this part does sound like a potential problem. When I write Bash scripts, I always use full paths, but I see where my having CDPATH set puts me at danger from other people's scripts. Technomancy gives a concrete example above. Although I think this is bad practice on their part (not to use full paths), I appreciate the warning.

            • pyre 15 years ago

              Does it implicitly export $CDPATH? Otherwise you would have to 'export CDPATH' to have that happen.

              • moe 15 years ago

                No, it does not. But in today's world of layered environments (virtualenv, rvm) your bashrc may very well be sourced in places that you didn't anticipate. On top of that each linux distribution has its own way of screwing with the environment files in creative ways, as anyone can attest who has had to make a cronjob work across platforms...

                However, your question suggests that you're probably one of the chosen few who could actually use this feature safely. My general advice against it was aimed at the 99% other people who think "Oh convenient!" without being fully aware of the implications.

              • telemachos 15 years ago

                The link I posted to suggests exporting CDPATH. I've always copied that, without really thinking about the effect on scripts. If you set (but don't export) CDPATH, it does not get passed along to scripts, as far as I can tell here.

                So, no, Bash doesn't implicitly export the variable. (Thanks to everyone for helping me improve my dotfiles a little bit.)

    • technomancy 15 years ago

      There are also a lot of scripts that assume CDPATH isn't being used; for instance any hadoop-based project will break if it's set.

coenhyde 15 years ago

I use this function in my bash profile to navigate to my projects from anywhere on the file system.

  function to {
    cd ~/Sites/$1/
  }
eg. cd ~/Sites/coenhyde.com

$ to coenhyde.com

  • orlandu63 15 years ago

    I would suggest mapping an alias instead of creating a function so that you will still be able to take advantage of parameter completion:

    > alias to='cd ~/Sites/'

    • coenhyde 15 years ago

      Ah, much nicer. Thankyou.

      Edit: On testing it doesn't work. 'to sitename' just goes straight to ~/Sites/. I knew there must have been a reason i used a function instead of an alias.

      • orlandu63 15 years ago

        Oh, that's right. 'to sitename' becomes 'cd ~/Sites/ sitename' which is not what you want. My apologies.

nevinera 15 years ago

    alias ba='vim ~/.bash_aliases; source ~/.bash_aliases'
Just make aliases for all the directories you go to a lot. I have twenty-something different aliases that start with 'cd'.

A bookmarking system seems like overkill to solve this problem.

oemera 15 years ago

Thank you for this awesome little script. However I found out that bashmarks doesn't work with folders which have whitespaces in the name.

For example:

  cd /Users/username/Library/Application\ Support
  s app_support
works great but if you do this it won't work:

  g app_support
I opened an issue on GitHub and after that I tried to fix it on my own. I never wrote a bash script and I'm really proud to have fixed this problem on my own.

Here are changes I made:

  # save current directory to bookmarks
  touch ~/.sdirs
  function s {
     cat ~/.sdirs | grep -v "export DIR_$1=" > ~/.sdirs1
     mv ~/.sdirs1 ~/.sdirs

     escaped_path=${PWD/ /\\ }
     echo "export DIR_$1=$escaped_path" >> ~/.sdirs
  }

  # jump to bookmark
  function g {
     source ~/.sdirs
     path=$(eval $(echo echo $(echo \$DIR_$1)))
  
     # replace whitespaces with "\ " for escaping
     escaped_path=${path/ /\\ }
     cd_eval="cd $escaped_path"
    
     eval $cd_eval
  }
Hope this helps you guys like it helped me. And if there is a way to do this in an more elegant way, please let me know. This would help me to improve my none existing bash skills :D

Edit: I opened up a fork and commited all my changes to this repo. I also opened a pull request and I hope my fix will get accepted.

GitHub fork: https://github.com/Oemera/bashmarks

Thanks

Ömer

noibl 15 years ago

I was just at the point of making a bunch of aliases for some long paths, to save my tab key from daily abuse. This is way more elegant. Thanks.

wanderr 15 years ago

Maybe it's just because I run a lot of the same commands and don't do a lot of development from the terminal, but I avoid cding at all usually and just type the full path. It svaes time over multiple sessions thanks to ctrl+r, and the commands in my history work no matter what dir I'm in.

  • pieceofpeace 15 years ago

    Ctrl-r is what I use too. Usually requires fewer keystrokes than other methods discussed here. And it works for all commands in shell history.

Groxx 15 years ago

A nice idea... I may end up using it, though a lot of my folders are the same name and I do like deterministic behavior.

In the meantime, this kicks the pants off separate Finder + Terminal action: http://decimus.net/DTerm/

sayemm 15 years ago

Interesting reading this because this is exactly why I love emacs, especially when I came across this tip a while ago: "Emacs: TRAMP + bookmarks = awesome", http://marc-abramowitz.com/archives/2006/03/12/emacs-tramp-b...

I'm always plugged in to my server with tramp and I've got multiple projects all bookmarked. It makes hopping around real easy, makes it feel like a browser more than an editor.

sever 15 years ago

I use the following scripts, both by Petar Marinov, they've saved me an enormous amount of keystrokes. One replaces CTRL-R history search, the other makes a much friendlier replacement for pushd and popd.

http://geocities.com/h2428/petar/bash_acd.htm

http://geocities.com/h2428/petar/bash_hist.htm

highly recommended.

charlieroot 15 years ago

1. How about we just learning to type fast(-er) and use file name completion

2. Use real shell like ksh, where history search actually works

3. cd $OLDPWD is occasionally helpful. Occasionally.

Kids...

clu3 15 years ago

I have usually a few dirs that i go back and forth frequently when coding, and I simply set them to my env. I add the following line to ~/.bashrc export lib='/path/to/my/lib' And 'cd $lib' will take me there. Very simple, and caters for most of my cd needs. Don't over-complicate things

bluishgreen 15 years ago

Back in 2009 I described another version of this here: http://www.commandlinefu.com/commands/view/117/fast-access-t...

rlpb 15 years ago

I use "m1=`pwd`" and then "cd $m1" for example. No setup required, although admittedly slightly more typing and the need to quote directories with spaces in them (rare for Unix sysadmin tasks for which I'm using a shell in the first place).

adsr 15 years ago

I manage with a combination of pushd/popd, cd - and terminal tabs most of the time.

netghost 15 years ago

If you're a programmer, you may find Qwandry useful: github.com/adamsanderson/qwandry

Instead of trying to remember where all your libraries are located, it will just open them up for you. Great for trying to debug misbehaving code.

philc 15 years ago

Additionally, try typing fewer characters when you cd in the general case: https://github.com/philc/fuzzycd

I've been using this for a few years and it's been a joy.

bherms 15 years ago

I use textexpander to keep from cd'ing everywhere... Just stick in a text expander snippet for directories I use a lot...

ie: hwst - cd /usr/Brad/Desktop/Dropbox/Brad/howas.it/repos/howasit_alpha/ etc...

slowpoison 15 years ago

The suggestion about putting "mdump" in .bash_logout, to automatically save all your bookmarks on exiting shell, is really useful.

Jach 15 years ago

I like this: https://github.com/MarcWeber/path-selector

pentarim 15 years ago

I cant remember my bookmarks so CTRL + R, then searching in history most of a time

jesstaa 15 years ago

Why not just use symlinks for your bookmarks? pushd and popd are also useful.

  • Nick_C 15 years ago

    I got bitten with symlinks for bookmarks. They don't change the PWD to the correct one. For example:

      cd /home/nick
      ln -s /var/www www
      cd www
      echo $PWD --->  /home/nick/www
    
    which will break scripts.
bretthellman 15 years ago

i wont

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection