July 30, 2007

Posted by John

Tagged shell, svn, and terminal

Older: Last Modified File in Directory

Newer: Label Helper Makes It Into Edge Rails

I Can Has Command Line?

If you are a good developer, you are constantly trying to improve your efficiency. There are tons of little tips and tricks that you pick up over time that help with that. One of the things that has helped me a lot is the command line. Coming from php land, I seriously lacked bash skills. Hopefully the goods to follow will edumacate you on the ways of the bash and it’s friend the profile.

History

iTerm Screenshot

Everytime you run a command it gets stored in history. You can view your history at anytime by typing history.

$ history
2  mxmlc Main.as 
3  mxmlc Main.as 
4  mxmlc Main.as 
# .... etc, etc, etc.

For a while, I would type history and then copy and paste the command in. Wrong. It’s much easier. You’ll notice the history prints each command with a number. You can run that command by number using !.

$ !4 # => runs mxmlc Main.as

That would run mxmlc Main.as (which was listed when I typed history). Nice eh? It’s the little things in life. That is nice and all but your history gets long over time (you can adjust the history size if you want). To deal with that use | (pipe) and grep in tandem like so:

$ history | grep svn
   89  svn_up_and_log
  198  svn st
  199  svn add db/migrate/004_create_locations.rb 
  201  svn st
  203  svn st
  205  svn commit -c svn-commit.tmp 
  206  svn commit --help
  207  svn commit -F svn-commit.tmp 
  208  svn st
  209  rm -f svn-commit.tmp 
  210  svn st
  213  svn st
  216  svn export http://stikkitresource.rubyforge.org/svn/trunk/

Instantly, you are presented with every history item that matches ‘svn’. You can then use ! to call the item. Another handy history shortcut is !!. It re-runs the last command you used. This might not seem super helpful until you use it with sudo. How many times to you type ‘gem install some_gem_name’ and you get a permission denied error. Then you have to retype it with sudo in front (or press up to see the previous command and ctrl-shift-a to go to the beginning of the line). Next time try this:

$ sudo !!

Your previous command is ran with sudo in front. No more permissions issue. A big thank you to Mr. Newland for that one.

Aliases

These are quite possibly my favorite when it comes to bashing. My bash_profile is stuff full of various shortcuts. I’m of the belief that if you are typing the same thing over and over and it is more than 4 characters, you should have an alias for it. Below are some aliases that I use:

###########
# GENERAL #
###########
alias home='cd ~' # the tilda is too hard to reach
alias l='ls -lah' # l for list style, a for all including hidden, h for human readable file sizes
alias h='history' # shortcut for history
alias c='clear' # shortcut to clear your terminal
alias ..='cd ..' # move up 1 dir
alias ...='cd ../..' # move up 2 dirs
alias ebash='mate ~/.bash_profile &' # because i edit my bash_profile a lot with new things
alias rbash='source ~/.bash_profile' # same as previous, after editing you have to source it for the new stuff to work

###########
# TEXTMATE #
###########
alias e='mate . &' # open current dir
alias et='mate README app/ config/ db/ lib/ public/ test/ vendor/plugins &' # open current dir assuming rails

#######
# SVN #
#######
alias sup='svn up' # trust me 3 chars makes a different
alias sst='svn st' # local file changes
alias sstu='svn st -u' # remote repository changes
alias scom='svn commit' # commit
alias svnclear='find . -name .svn -print0 | xargs -0 rm -rf' # removes all .svn folders from directory recursively
alias svnaddall='svn status | grep "^\?" | awk "{print \$2}" | xargs svn add' # adds all unadded files

########
# RUBY #
########
alias irb='irb --readline -r irb/completion -rubygems' # use readline, completion and require rubygems by default for irb
# really awesome function, use: cdgem <gem name>, cd's into your gems directory and opens gem that best matches the gem name provided
function cdgem {
  cd /opt/local/lib/ruby/gems/1.8/gems/; cd `ls|grep $1|sort|tail -1`
}

#########
# RAILS #
#########
alias ss='mongrel_rails start' # start up the beast
alias sc='script/console' # obvious
alias a='autotest -rails' # makes autotesting even quicker
# see http://railstips.org/2007/5/31/even-edgier-than-edge-rails
function edgie() { 
  ruby ~/rails/trunk/railties/bin/rails $1 && cd $1 && ln -s ~/rails/trunk vendor/rails && mate . 
}

#########
# MYSQL #
#########
alias mysql=mysql5 # so i can use mysql command and don't have to type the 5 :) i'm lazy

So that was a lot to soak in but let me assure you it’s worth it. I’m sure others have even better aliases than me. You don’t have to put aliases in your .bash_profile. You can actually put them in .bash_aliases. If .bash_aliases doesn’t automatically get loaded, you can add this to your bash profile to force it to load:

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

SSH

Before rails and capistrano, I think I ssh’d maybe 20 times in my life. Since then, ssh is probably one of the things I use most from the command line. In fact, a little known secret is that ssh will get you the ladies (LLSSH for the Cool J fans). You probably know that you can ssh to a host like so:

ssh deploy@myfancydomain.com

You may not know that you can make shortcuts for you ssh accounts. Follow along:

$ mate ~/.ssh/config

# put the following in the file
Host nsync
HostName nsync.com
User jtimb

Now you can ‘ssh nsync’ from the command line and it will behave equivalent to ‘ssh jtimb@nsync.com’. You can put several of these shortcuts in the config file and there are other options but I’ll let you research those on your own.

SSH Config File

Key pairs are also an ssh must but others have covered it far better than I could.

Dotfiles

DotFiles.org

You have sworn a solemn oath to never again type more than 4 chars from the command line. Cool. So where can you find more tricks from people far more bashish than I? A good place to start is a simple little camping app named dotfiles.org. Dotfiles has several different types of files that you can pour through to find even more functions, aliases and shortcuts.

Congratulations, you have been edumacated on the command line. Have a better one than me? Are any of mine wrong or could be improved? Let me know in the comments.

24 Comments

  1. You can also use strings after ! and it will run the last matched command

    eg.
    !ssh (will run the most recent command starting with ssh)
    !s (will run the most recent command starting with s)

    etc.

  2. I use “CTRL-R” for history. Once you’ve hit “CTRL-R”, you can start typing and it will do sub-string matching on your history file. Eg. “CTRL-R ssh”

    You can keep hitting “CTRL-R” to cycle through other matches, so “CTRL-R ssh CTRL-R” will give you second-last “ssh” command you ran.

  3. Seng Ming Seng Ming

    Jul 30, 2007

    Thanks for the information on .ssh/config, I never even thought of that after so many years of using ssh. By the way, you might also find this useful

    http://drawohara.tumblr.com/post/6584031

  4. badcarl badcarl

    Jul 30, 2007

    I always map my caps lock to ctrl because who uses caps lock anyway?

    Then at the command line you can use emacs style shortcuts like ctrl+p and ctrl+n for arrow up and arrow down and ctrl+a, ctrl+e for beginning/end of line.

    On a Mac, these work in almost all applications. I find using these shortcuts is more natural and faster than arrow keys.

  5. Oooh, thanks for the reminder about edgie – that’s very cool.

  6. alias home=‘cd ~’ # the tilda is too hard to reach

    .. no need for that. `cd` on its own takes you home.

    alias c=‘clear’ # shortcut to clear your terminal

    .. try CTRL-l (that’s the letter ell), or CMD-K. SLightly different but both useful.

    And another nice trick to add to the top of your .ssh/config. The following sets up ControlMaster multiplexing, so you can tunnel subsequent ssh connections over the first.

    Host *
    ControlMaster auto
    ControlPath ~/.ssh/master-%r@%h:%p

  7. One of my favourite things in bash is !$. This is the last parameter of the last command. Comes in handy much more often than you might think.

  8. Minor things:

    If you’ve mongrel installed, script/server will actually use that. mongrel_rails start works as well, but you don’t get automagic log output to the console as with script/server.

    Using .irbrc is IMO tidier than aliasing the irb command.

    The cdgem function was very nice – thanks. I changed it to do cd "$GEM_HOME/gems"; since I’ve set that environment variable to have gems installed somewhere else.

  9. Eep, rogue link tag. Sorry about that. Guess I found a bug ;)

  10. Yay! Great shortcuts :D

    My dumb mind didn’t think of aliasing all this stuff which for the most part I do all the time :/

    I added

    function hf() {
    history | grep $1
    }

    which is a pattern I use constantly (together with ^R)

  11. @Justin – Awesome.

    @Nathan – Wow. Really cool.

    @Seng – Yep, I saw that. It doesn’t complete with the user you are ssh’ing as. I was going to tinker with a script to do that from your history until Nathan posted his tip.

    @noodl – Much slicker. Wondered how people did it in screencasts without spelling clear. :)

    @Henrik N – yep, i know but I use topfunky’s hodel 3000 compliant logger which doesn’t like script/server and mongrel for some reason.

    @Nicolas Sanguinetti – Cool. It’s funny how I type that all the time too but haven’t made a shortcut for it.

  12. Could you share which terminal sotware are u using? It’s Coda from Panic? or something like that?

  13. Could you share which terminal sotware are u using?

    It’s iTerm, isn’t it?

  14. Yes, it’s iterm. The latest release is quite snappy compared to some older versions. I love me some tabs.

  15. Nice article – I’ve been looking for dotfiles.org for a few days now – I knew I’d seen it before, but couldn’t remember the name!

    Incidentally, do you have any idea how to use the “synchronization features” that dotfiles.org claims to have? They talk about a command-line client, but it seems like it’s vapour at the moment…

  16. @James – Hmm. No, I don’t know where the sync is. You could look at the forms that they have and probably pretty easily create something that would sync with www::mechanize or something.

  17. I would add that the built-in bash command ‘hash’ is fun to see what you have been running in that window, and how often.

    I’ve gotten into the habit of checking in all my dot-files and scripts into subversion, so it’s super-easy to get set up on a new box, and to keep all your accounts consistent.

  18. Thanks for the dotfiles.org plug! And hey, I learned something (!!)… that’s why I love the command line, it’s as simple or as infinitely complex as you want to make it.

  19. Thanks for the ssh tip.

    I used it and needed to have add a port. So I did what I never do … the obvious. Thought I’d pass it along.

    Host nsync
    Hostname nsync.com
    Port 3000
    User jed

  20. Quick, stoopid question time: what terminal app is that you’re using?

  21. iTerm.

  22. I use lots of aliases in my .bashrc as well.

    I like to have 10,000 lines in my history file and the current history number in PS1 so I can bang ! a command from the history.

    In .bashrc


    export HISTFILE=~/.bash_history
    export HISTFILESIZE=10000
    export HISTSIZE=10000
    export PS1=‘\u@\h \! \w\$ ’
    alias his=’history | grep $1’

    Then I can find a command that I want to run again without typing it out:

    mike@bent 10032 ~$ his vim
    ....
     9665  vim /usr/local/lib/ruby/gems/1.8/gems/rv-3.1/lib/rv.rb 
     9667  vim /usr/local/lib/ruby/gems/1.8/gems/rv-3.1/lib/rv_harness.rb
     9669  vim /usr/local/lib/ruby/gems/1.8/gems/camping-1.5/lib/camping-unabridged.rb 
     9670  vim /usr/local/lib/ruby/gems/1.8/gems/camping-1.5/lib/camping/session.rb 
    ....
    mike@bent 10033 ~$ !9669
    

    So with !9669 I would have vimed camping-unabridged.rb again.

    Here is my current .irbrc which brings in some Bash-like features:

    http://pastie.caboo.se/pastes/102231

  23. To speed things up a bit more try using the —wait or -w flag with TextMate. With this TextMate waits for file to be closed before running the next command. So to update my bash profile i use:

    alias ebash='mate -w ~/.bash_profile; source ~/.bash_profile'

  24. good stuff.

Sorry, comments are closed for this article to ease the burden of pruning spam.

About

Authored by John Nunemaker (Noo-neh-maker), a programmer who has fallen deeply in love with Ruby. Learn More.

Projects

Flipper
Release your software more often with fewer problems.
Flip your features.