Search

Enter a search word or two and press return to see the search results.

Who am I?

Hi, I’m Graeme and these are my notes, from my messy desk. I started this blog because Google proved to be more useful at finding content than anything else I’ve used.

So I started adding my own content in the hopes that Google would index it and allow me to find things again in the future.

It works.

You can find out more about me here, and you should follow me on Twitter here.

Keeping up

You can automatically receive new content here by subscribing to the “Blog RSS” (link below). This is the easiest way to keep up with what I write here.  See this BBC article for a good introduction on RSS and keeping up with the goings on of the Internet more easily.

« Tabular FormBuilder for easily creating forms in Rails | Main | Wedding Photo picks »
Wednesday
12Jul2006

Using the shell within irb

A couple of weeks ago, I had a little diversion, playing around with the shell bits and pieces in Ruby core. And it sounded like it could be quite handy for when you're in that IRB session and don't want to quit/reload (or switch to another terminal, I guess). So I added a few widgets to by `~/.irbrc` to make it work well for me. You can find the relevant parts in [`shell_from_irb.rb`](/dist/shell_from_irb.rb). Probably the easiest thing to do is copy and paste the contents into your own `~/.irbrc`.

So, how do you use it? From the irb shell:

irb(main):003:0> shell.echo 'hello world'
=> hello world

Or, something more useful which will return you an array of files you've modified since your last commit to subversion:

irb(main):016:0> shell.svn(:stat).grep(/^M/).collect do |line|
irb(main):017:1* line.gsub(/^M */, '').chomp
irb(main):018:1> end
=> ["app/helpers/application_helper.rb",
"app/controllers/application.rb",
"config/photography_config.rb",
"public/javascripts/lightbox.js",
"public/stylesheets/lightbox.css"]

Oh, and since all the shell commands in your path are now effectively methods, if you have readline and completion switched on, you can do what you'd usually do in the shell:

irb(main):019:0> shell.sv[tab][tab]
shell.svk shell.svnadmin shell.svnserve
shell.svm shell.svndiffshim_py shell.svnversion
shell.svn shell.svndumpfilter
shell.svn_backup_sh shell.svnlook
irb(main):019:0> shell.sv

I've made a few modifications to the default behaviour of the `shell` widget in Ruby core. I'm installing the commands with no prefix, so that it's easier to use. By default, however, that would override the implementation of a function with the latest one found. The default behaviour of the shell is to use the *first* match, so I've fiddled things so that it also uses the first match. This has the added benefit that it doesn't override `Shell`'s internal implemtation of things like `pwd` which otherwise causes the thing to completely break (since it's also *used* internally). That's what `FixAddDelegateCommandToShell` does, for those of you playing along at home.

I've also allowed you to specify arguments to system commands as symbols. It feels more natural to me to type `shell.svn :stat` than `shell.svn 'stat'`. I guess YMMV.

Lastly, it's all wrapped up in a singleton widget which lazily loads the shell functionality. That makes it available any time, but pushes the time hit (where it scans `$PATH` and creates all those methods for each command) to the first use, rather than when you launch `irb`.

So there you go. I've found it useful, so I thought I'd share.

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments (7)

IRB FTW!

Haha, this makes the complete transition to ruby a breezer :P

July 12, 2006 | Unregistered Commenteralbert ramstedt

I got this error message

NoMethodError: undefined method `install_system_commands' for Shell:Class

I just used the posted code from shell_from_irb.rb

July 13, 2006 | Unregistered CommenterAndy

Ok, got it.

require 'shell'

July 13, 2006 | Unregistered CommenterAndy

Andy: Ah, oops, I forgot to include that bit (I've got require 'shell' way further up my ~/.irbrc). I've fixed the copy here now, too. Thanks!

July 13, 2006 | Unregistered Commentermathie

Apart from tab completion, I can't see what this does that you can't do with backticks?

Take your example with modified svn files. This does the same thing:

`svn stat`.grep(/^M/) { |x| x.sub(/^M */, '').chomp }

July 16, 2006 | Unregistered CommenterPer Melin

you could simply use ^Z to pause the job and use the shell then getting back to it with %n

July 17, 2006 | Unregistered Commenterdam

Per, Dam: Picky, picky. My solution is sooo much prettier. :-)

July 17, 2006 | Unregistered Commentermathie

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>