Here's my solution, with a sample run.

Comments, corrections, criticism welcome.
/dh

$ ./blackjack.rb
Odds for each dealer outcome based on initial upcard (2 deck game)
      17     18     19     20     21    BUST
  A  12.58% 12.82% 12.75% 12.85% 36.07% 12.93%
  2  13.93% 13.33% 13.07% 12.39% 11.92% 35.36%
  3  13.27% 13.06% 12.45% 12.18% 11.53% 37.50%
  4  13.07% 12.02% 12.10% 11.63% 11.31% 39.88%
  5  12.10% 12.28% 11.73% 10.90% 10.73% 42.25%
  6  16.62% 10.62% 10.67% 10.12%  9.75% 42.21%
  7  37.05% 13.82%  7.80%  7.88%  7.34% 26.11%
  8  12.97% 36.12% 12.90%  6.89%  6.96% 24.16%
  9  12.09% 11.20% 35.41% 12.11%  6.10% 23.09%
10  11.29% 11.22% 11.30% 33.56% 11.31% 21.32%
  J  11.29% 11.22% 11.30% 33.56% 11.31% 21.32%
  Q  11.29% 11.22% 11.30% 33.56% 11.31% 21.32%
  K  11.29% 11.22% 11.30% 33.56% 11.31% 21.32%

$ cat blackjack.rb
#!/usr/bin/env ruby

CARDS = %w(A 2 3 4 5 6 7 8 9 10 J Q K)
DECKS = ARGV.size == 1 ? ARGV[0].to_i : 2
SUITS = 4

def hand_value(hand)
   value = 0
   # First calculate values ignoring aces
   hand.each do |c|
     if c=='A'
       next
     elsif 'JQK'.include? c
       value += 10
     else
       value += c.to_i
     end
   end
   # Then add aces as 11 unless they would bust the hand
   hand.each do |c|
     if c=='A'
       if value>10
         value += 1
       else
         value += 11
       end
     end
   end
   value
end

def new_shute
   cards = []
   CARDS.each do |c|
     DECKS.times { SUITS.times { cards << c }}
   end
   cards
end

def odds_of(cards, v)
   count = 0
   cards.each { |c| count += 1 if c==v }
   (1.0 * count) / cards.length
end

# calc the odds of reaching result from a given hand
def calc_odds(hand, result)
   current = hand_value(hand)
   return 1.0 if current == result
   return 0.0 if current >= 17

   # Remove hand cards from full shute
   cards = new_shute
   hand.each {|c| cards.delete_at(cards.index(c))}

   odds = 0.0
   CARDS.each do |c|
     odds_of_card = odds_of(cards, c)
     if odds_of_card > 0.0
       hand.push c
       odds_of_result = calc_odds(hand, result)
       odds += odds_of_card * odds_of_result
       hand.pop
     end
   end

   return odds
end

puts "Odds for each dealer outcome based on initial upcard (#{DECKS}  
deck game)"

puts "     17     18     19     20     21    BUST"
CARDS.each do |c|
   odds = {}
   bust = 100.0
   (17..21).each do |r|
     odds[r] = calc_odds([c], r) * 100.0
     bust -= odds[r]
   end
   printf "%2s  %5.02f%% %5.02f%% %5.02f%% %5.02f%% %5.02f%% %5.02f%% 
\n", c, odds[17], odds[18], odds[19], odds[20], odds[21], bust
end