Cryptic Dollar Variables & Their Meanings in Ruby

Written by

Ruby is filled with a set of cryptic variables. These predefined global constants give access to all kinds of interesting information. They’re also accessible via slightly less cryptic constants. As a finally note, it’s not always a great idea to use these variables, many of them are accessible or modifiable via more conventional and readable forms. I’ve attempted to demonstrate each global variable in irb. Without further ado, Ruby Global Variables:

Global Process Variables in Ruby

These give information about the currently running ruby process

$$ aka $PID aka $PROCESS_ID

The $$ variable gives the currently running process id

>> $$
=> 17376

Look at this code to kill to a process from that process:

> irb
>> `kill -9 #{$$}`
[1]    17376 killed     irb

$? aka $CHILD_STATUS

The $? gives the status of the last running child process

>> `echo hello`
=> "hello\n"
>> $?
=> #<Process::Status: pid 17861 exit 0>
>> $?.success?
=> true

Exceptions and Errors

These are variables related to exceptions and errors in ruby

$! aka $ERROR_INFO

The $! is the info paused to the the raise. For example in raise 'there\'s no peanut butter', we’re talking about the there's no peanut butter part.

>> begin raise "this town ain't big enough for the both of us" rescue puts $! end 
this town ain't big enough for the both of us
=> nil

$@ aka $ERROR_POSITION

The $@ variable gives a complete stack trace to where an error occurred. Since it’s an array, if you want to see the contents of each piece of a the trace you have to iterate over it.

>> begin raise 'no soup in kitchen' rescue $@.each { |trace| puts trace } end
(irb):7:in `irb_binding'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/workspace.rb:80:in `evaluate'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/context.rb:254:in `evaluate'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:159:in `block (2 levels) in eval_input'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:273:in `signal_status'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:156:in `block in eval_input'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:243:in `block (2 levels) in each_top_level_statement'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:155:in `eval_input'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:70:in `block in start'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `catch'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `start'
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
=> ["(irb):7:in `irb_binding'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/workspace.rb:80:in `evaluate'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/context.rb:254:in `evaluate'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:159:in `block (2 levels) in eval_input'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:273:in `signal_status'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:156:in `block in eval_input'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:243:in `block (2 levels) in each_top_level_statement'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:155:in `eval_input'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:70:in `block in start'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `catch'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `start'", "/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'"]

Strings & separators

These global variables are about how ruby handles strings and the separators it uses when splitting or joining them.

$; aka $FS aka $FIELD_SEPARATOR

This is the pattern that is used in String.split. It defaults to being set to a space.

>> "One Spaceship, Two Tiny Tanks, Three Misplaced Socks".split
=> ["One", "Spaceship,", "Two", "Tiny", "Tanks,", "Three", "Misplaced", "Socks"]
>> $; = ","
=> ","
>> "One Spaceship, Two Tiny Tanks, Three Misplaced Socks".split
=> ["One Spaceship", " Two Tiny Tanks", " Three Misplaced Socks"]

$, aka $OFS aka $OUTPUT_FIELD_SEPARATOR

$, is the global variable for the output when Array.join and Kernel.print are called. It defaults to nil

>> ['one', 'two', 'three', 'green'].join
=> "onetwothreegreen"
>> $, = "-"
=> "-"
>> ['one', 'two', 'three', 'green'].join
=> "one-two-three-green"

$/ aka $RS aka $INPUT_RECORD_SEPARATOR

$/ is the input record separator. It gets used when Kernel.gets is called. It’s usually newline, but it can be tweaked. This one is difficult to show because irb relies on \n being the record separator. If $/ is set to nil then gets will read an entire file.

$\ aka aka $ORS aka $OUTPUT_RECORD_SEPARATOR

$\ is a variable is that a String that is appended tot he

>> $\ = "mooooooo "
=> "mooooooo "
>> puts a
NameError: undefined local variable or method `a' for main:Object
mooooooo        from (irb):6
        from /Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
mooooooo >> a

Files

These global variables about where ruby is in reading a file. To demonstrate these I have a filled called letter.txt that looks like this:

Dear Caroline,
I think we need some honey for tea.
I also think that I may have misplaced my red tie, have you seen it?

-Nick

$. aka $INPUT_LINE_NUMBER aka $NR

$. is the line number of the file being read.

>> open('letter.txt').each { |line| puts "#{$.}: #{line}" }
1: Dear Caroline,
2: I think we need some honey for tea.
3: I also think that I may have misplaced my red tie, have you seen it?
4: 
5: -Nick
=> #<File:letter.txt>

$_ aka $LAST_READ_LINE

$_ is the last read line.

>> open('letter.txt').each { |line| puts $_.nil? }
true
true
true
true
true

The last read line is always nil because ruby is looking for a nil terminated file.

Matching & Regular Expressions

$~ aka $LAST_MATCH_INFO

This is the last match information on a regular expression, if there was one. It returns an instance of MatchData or nil.

>> "the robots are coming, the robots are coming, the robots are coming" =~ /ro/
=> 4
>> $~
=> #<MatchData "ro">
>> $~.to_s
=> "ro"
>> "the robots are coming, the robots are coming, the robots are coming" =~ /cats/
=> nil
>> $~
=> nil

$& aka $MATCH

$& is very similar to $~, instead of returning an instance of MatchData, $& returns the last matched String.

>> "the robots are coming, the robots are coming, the robots are coming" =~ /ro/
=> 4
>> $&
=> "ro"

$\\ aka $PREMATCH

$\ is the string that came before the match.

>> "There were once ten tin robots standing in a row." =~ /robot/
=> 24
>> $`
=> "There were once ten tin "

$' aka $POSTMATCH

$‘ is the string that came after a match.

>> "There were once ten tin robots standing in a row." =~ /robot/
=> 24
>> $'
=> "s standing in a row."

Misc

$> aka $DEFAULT_OUTPUT

This is where ruby is writing by default, it’s used by Kernel.print

>> $> = $stderr
=> #<IO:<STDERR>>
>> puts 'no no no'
no no no
=> nil
>> $> = $stdin
/Users/nicholasrowe/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:168:in `write': not opened for writing (IOError)

This is also a good time to point out $stderr, $stdout, $stdin these variables are the current standard error, standard output, and standard input. As you saw above you can’t set an output to an input.

$* aka $ARGV

$* is probably the most commonly seen global variable seen in ruby. It’s the arguments that were passed to the ruby file, as an array. To demonstrate this, I’ve created a script called argument_echoer.rb it looks like this:

$*.each { |arg| puts arg }

And when it’s run looks like this:

> ruby argument_echoer.rb Who What When Where and Why 
Who
What
When
Where
and
Why

It’s worth noting that if you pass arguments to the ruby that those arguments will have been omitted from the list.

Comments or Questions? Contact Nick @nixterrimus on twitter.

Nick is a software engineer, geek, web enthusaist, open source contributor, home automation tinkerer, ocean admirer and all around general optimist living in San Francisco. Want to get in touch about professional matters? Nick Rowe is also available on LinkedIn.