Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Command-line Ruby

jeg2
February 22, 2013

Command-line Ruby

A discussion about ways to learn Ruby faster and one possible avenue for doing that.

jeg2

February 22, 2013
Tweet

More Decks by jeg2

Other Decks in Technology

Transcript

  1. James Edward Gray II ✤ I am a regular panelist

    on The Ruby Rogues podcast ✤ I was a Rubyist before Rails shipped and made us popular ✤ I have written a lot of code and documentation for Ruby, including the standard CSV library
  2. I Suspect You’ve Been Learning… ✤ How clean code helps

    you manage complexity ✤ How well written code eases communication with others ✤ How to identify and improve problem spots in your code
  3. This Is For Your Own Good! Ugly Ruby Strap In

    Folks, This Could Get Weird
  4. What If… ✤ Our goal isn’t to write the best

    code possible? ✤ Our goal is to do a big chunk of work quickly? ✤ Our goal is to learn Ruby faster?
  5. The Wheel of Time ✤ A fantasy series from my

    childhood ✤ The female magic users have a strict training process built up over 100’s of years of magic use ✤ The male magic users, brand new to magic, try to catch up by using it for everything: cooking, chores, etc.
  6. The -e (execute) Switch $ ruby -e 'p 21 *

    2' 42 $ ruby -e 'p "some data"' "some data" $ ruby -e 'var = 42; p var' 42 ✤ Run some Ruby without a script ✤ Hints: ✤ Use ‘…’ for shell quoting and “…” for Ruby quoting (to minimize escaping) ✤ Use ;’s to get multiple lines
  7. The -e (execute) Switch $ ruby -e 'p 21 *

    2' 42 $ ruby -e 'p "some data"' "some data" $ ruby -e 'var = 42; p var' 42 ✤ Run some Ruby without a script ✤ Hints: ✤ Use ‘…’ for shell quoting and “…” for Ruby quoting (to minimize escaping) ✤ Use ;’s to get multiple lines
  8. The -e (execute) Switch $ ruby -e 'p 21 *

    2' 42 $ ruby -e 'p "some data"' "some data" $ ruby -e 'var = 42; p var' 42 ✤ Run some Ruby without a script ✤ Hints: ✤ Use ‘…’ for shell quoting and “…” for Ruby quoting (to minimize escaping) ✤ Use ;’s to get multiple lines
  9. The -e (execute) Switch $ ruby -e 'p 21 *

    2' 42 $ ruby -e 'p "some data"' "some data" $ ruby -e 'var = 42; p var' 42 ✤ Run some Ruby without a script ✤ Hints: ✤ Use ‘…’ for shell quoting and “…” for Ruby quoting (to minimize escaping) ✤ Use ;’s to get multiple lines
  10. The “Unix Filter” Pattern ✤ Accepts a file name on

    the command-line ✤ Or multiple names at once ✤ Or reads from STDIN ✤ Writes to STDOUT $ echo 'A line from file_1.' > file_1.txt $ echo 'A line from file_2.' > file_2.txt $ cat file_1.txt A line from file_1. $ cat file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | cat A line from $stdin.
  11. The “Unix Filter” Pattern ✤ Accepts a file name on

    the command-line ✤ Or multiple names at once ✤ Or reads from STDIN ✤ Writes to STDOUT $ echo 'A line from file_1.' > file_1.txt $ echo 'A line from file_2.' > file_2.txt $ cat file_1.txt A line from file_1. $ cat file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | cat A line from $stdin.
  12. The “Unix Filter” Pattern ✤ Accepts a file name on

    the command-line ✤ Or multiple names at once ✤ Or reads from STDIN ✤ Writes to STDOUT $ echo 'A line from file_1.' > file_1.txt $ echo 'A line from file_2.' > file_2.txt $ cat file_1.txt A line from file_1. $ cat file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | cat A line from $stdin.
  13. The “Unix Filter” Pattern ✤ Accepts a file name on

    the command-line ✤ Or multiple names at once ✤ Or reads from STDIN ✤ Writes to STDOUT $ echo 'A line from file_1.' > file_1.txt $ echo 'A line from file_2.' > file_2.txt $ cat file_1.txt A line from file_1. $ cat file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | cat A line from $stdin.
  14. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  15. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  16. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  17. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  18. Ruby’s ARGF ✤ ARGF means use ARGV to build a

    Unix Filter ✤ It supports the standard Unix Filter patterns ✤ You can use it like an IO object $ ruby -e 'puts ARGF.read' file_1.txt A line from file_1. $ ruby -e 'puts ARGF.read' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts ARGF.read' A line from $stdin.
  19. Kernel#gets ✤ Ruby’s default “get a line of input” method

    ✤ Available everywhere ✤ It reads from ARGF ✤ You get a Unix Filter for free $ ruby -e 'puts gets' file_1.txt A line from file_1. $ ruby -e '2.times do puts gets end' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts gets' A line from $stdin.
  20. Kernel#gets ✤ Ruby’s default “get a line of input” method

    ✤ Available everywhere ✤ It reads from ARGF ✤ You get a Unix Filter for free $ ruby -e 'puts gets' file_1.txt A line from file_1. $ ruby -e '2.times do puts gets end' file_1.txt file_2.txt A line from file_1. A line from file_2. $ echo 'A line from $stdin.' | ruby -e 'puts gets' A line from $stdin.
  21. The Current Line Variable: $_ ✤ Ruby has a special

    variable for “the current line:” $_ ✤ Note how it looks like a line ✤ Kernel#gets assigns to $_ ✤ Kernel#print prints $_ if no arguments are given $ ruby -e 'gets; print' file_1.txt A line from file_1. $ ruby -e 'gets; $_.tr! " ", "+"; print' file_1.txt A+line+from+file_1.
  22. The Current Line Variable: $_ ✤ Ruby has a special

    variable for “the current line:” $_ ✤ Note how it looks like a line ✤ Kernel#gets assigns to $_ ✤ Kernel#print prints $_ if no arguments are given $ ruby -e 'gets; print' file_1.txt A line from file_1. $ ruby -e 'gets; $_.tr! " ", "+"; print' file_1.txt A+line+from+file_1.
  23. The Current Line Variable: $_ ✤ Ruby has a special

    variable for “the current line:” $_ ✤ Note how it looks like a line ✤ Kernel#gets assigns to $_ ✤ Kernel#print prints $_ if no arguments are given $ ruby -e 'gets; print' file_1.txt A line from file_1. $ ruby -e 'gets; $_.tr! " ", "+"; print' file_1.txt A+line+from+file_1.
  24. The Current Line Variable: $_ ✤ Ruby has a special

    variable for “the current line:” $_ ✤ Note how it looks like a line ✤ Kernel#gets assigns to $_ ✤ Kernel#print prints $_ if no arguments are given $ ruby -e 'gets; print' file_1.txt A line from file_1. $ ruby -e 'gets; $_.tr! " ", "+"; print' file_1.txt A+line+from+file_1.
  25. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  26. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  27. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  28. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  29. The -p (print loop) Switch ✤ -p wraps -e code

    in a loop that: ✤ reads a line ✤ runs the -e code ✤ prints the line while gets # -e code goes here print end $ ruby -pe '# do nothing' file_1.txt file_2.txt A line from file_1. A line from file_2. $ ruby -pe '$_ = "Line #{ARGF.lineno}\n"' file_1.txt file_2.txt Line 1 Line 2
  30. The -n (non-print loop) Switch ✤ Same as -p, but

    it doesn’t print ✤ This allows you to decide when to print $ ruby -ne 'print if $_ =~ /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  31. The -n (non-print loop) Switch ✤ Same as -p, but

    it doesn’t print ✤ This allows you to decide when to print $ ruby -ne 'print if $_ =~ /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  32. The -n (non-print loop) Switch ✤ Same as -p, but

    it doesn’t print ✤ This allows you to decide when to print $ ruby -ne 'print if $_ =~ /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  33. A Bare Regexp Conditional ✤ My last example can be

    shortened ✤ A bare Regexp conditional is assumed to be a test against $_ $ ruby -ne 'print if /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  34. A Bare Regexp Conditional ✤ My last example can be

    shortened ✤ A bare Regexp conditional is assumed to be a test against $_ $ ruby -ne 'print if /2\.\Z/' file_1.txt file_2.txt A line from file_2.
  35. The “Flip-flop” Operator ✤ A conditional can also be a

    Range of two Regexp objects ✤ It “turns on” when the first matches and will stay true until the second matches $ ruby -e 'puts %w[one two three four five six]' > numbers.txt $ ruby -ne 'print if /\A[os]/../ee\Z/' numbers.txt one two three six
  36. The “Flip-flop” Operator ✤ A conditional can also be a

    Range of two Regexp objects ✤ It “turns on” when the first matches and will stay true until the second matches $ ruby -e 'puts %w[one two three four five six]' > numbers.txt $ ruby -ne 'print if /\A[os]/../ee\Z/' numbers.txt one two three six
  37. The -i (in place edit) Switch ✤ Passing -i turns

    causes your filter to replace the input itself ✤ This is done with a buffer, so it feels like you are reading from and writing to the same place $ cat numbers.txt one two three four five six $ ruby -pi \ > -e '$_.tr! "aeiou", "X"' \ > numbers.txt $ cat numbers.txt XnX twX thrXX fXXr fXvX sXx
  38. The -i (in place edit) Switch ✤ Passing -i turns

    causes your filter to replace the input itself ✤ This is done with a buffer, so it feels like you are reading from and writing to the same place $ cat numbers.txt one two three four five six $ ruby -pi \ > -e '$_.tr! "aeiou", "X"' \ > numbers.txt $ cat numbers.txt XnX twX thrXX fXXr fXvX sXx
  39. The -i (in place edit) Switch ✤ Passing -i turns

    causes your filter to replace the input itself ✤ This is done with a buffer, so it feels like you are reading from and writing to the same place $ cat numbers.txt one two three four five six $ ruby -pi \ > -e '$_.tr! "aeiou", "X"' \ > numbers.txt $ cat numbers.txt XnX twX thrXX fXXr fXvX sXx
  40. Now With Backups ✤ -i can also accept a backup

    argument ✤ The original content is moved into a file with the backup suffix appended ✤ This can really protect you when you try to make sweeping changes with some gnarly Regexp! $ ruby -pi.bak \ > -e '$_.delete! "X"' \ > numbers.txt $ cat numbers.txt n tw thr fr fv sx $ cat numbers.txt.bak XnX twX thrXX fXXr fXvX sXx
  41. Now With Backups ✤ -i can also accept a backup

    argument ✤ The original content is moved into a file with the backup suffix appended ✤ This can really protect you when you try to make sweeping changes with some gnarly Regexp! $ ruby -pi.bak \ > -e '$_.delete! "X"' \ > numbers.txt $ cat numbers.txt n tw thr fr fv sx $ cat numbers.txt.bak XnX twX thrXX fXXr fXvX sXx
  42. Now With Backups ✤ -i can also accept a backup

    argument ✤ The original content is moved into a file with the backup suffix appended ✤ This can really protect you when you try to make sweeping changes with some gnarly Regexp! $ ruby -pi.bak \ > -e '$_.delete! "X"' \ > numbers.txt $ cat numbers.txt n tw thr fr fv sx $ cat numbers.txt.bak XnX twX thrXX fXXr fXvX sXx
  43. Now With Backups ✤ -i can also accept a backup

    argument ✤ The original content is moved into a file with the backup suffix appended ✤ This can really protect you when you try to make sweeping changes with some gnarly Regexp! $ ruby -pi.bak \ > -e '$_.delete! "X"' \ > numbers.txt $ cat numbers.txt n tw thr fr fv sx $ cat numbers.txt.bak XnX twX thrXX fXXr fXvX sXx
  44. The -a (autosplit) Switch ✤ -a will cause $_ to

    be split() into $F (fields) with each read ✤ By default, split() uses a pattern like: /\s+/ $ ruby -e 'puts "some spaced\tfields"' | \ > ruby -nae 'p $F' ["some", "spaced", "fields"]
  45. The -a (autosplit) Switch ✤ -a will cause $_ to

    be split() into $F (fields) with each read ✤ By default, split() uses a pattern like: /\s+/ $ ruby -e 'puts "some spaced\tfields"' | \ > ruby -nae 'p $F' ["some", "spaced", "fields"]
  46. The -a (autosplit) Switch ✤ -a will cause $_ to

    be split() into $F (fields) with each read ✤ By default, split() uses a pattern like: /\s+/ $ ruby -e 'puts "some spaced\tfields"' | \ > ruby -nae 'p $F' ["some", "spaced", "fields"]
  47. The -F (field separator) Switch ✤ Used with -a, -F

    will let you change the split() pattern ✤ WARNING: this is a weird old switch that doesn’t allow a space before the pattern starts! $ echo "1,2, 3" | \ > ruby -naF',\s*' -e 'p $F' ["1", "2", "3\n"]
  48. The -F (field separator) Switch ✤ Used with -a, -F

    will let you change the split() pattern ✤ WARNING: this is a weird old switch that doesn’t allow a space before the pattern starts! $ echo "1,2, 3" | \ > ruby -naF',\s*' -e 'p $F' ["1", "2", "3\n"]
  49. The -F (field separator) Switch ✤ Used with -a, -F

    will let you change the split() pattern ✤ WARNING: this is a weird old switch that doesn’t allow a space before the pattern starts! $ echo "1,2, 3" | \ > ruby -naF',\s*' -e 'p $F' ["1", "2", "3\n"]
  50. The -l (line ending) Switch ✤ -l trims the line

    ending off of read input ✤ The record separator (Ruby’s idea of a line ending) can be changed by passing an octal character code to -0 (not shown) $ echo "1,2, 3" | \ > ruby -nalF',\s*' -e 'p $F' ["1", "2", "3"]
  51. The -l (line ending) Switch ✤ -l trims the line

    ending off of read input ✤ The record separator (Ruby’s idea of a line ending) can be changed by passing an octal character code to -0 (not shown) $ echo "1,2, 3" | \ > ruby -nalF',\s*' -e 'p $F' ["1", "2", "3"]
  52. The Choice is Yours ✤ You could take the blue

    pill and pretend Ruby is always beautiful, without any of these ugly features ✤ You could take the red pill, go further down the rabbit hole, and learn yourself some command-line Ruby wizardry
  53. For Those Who Like Red Pills ✤ Learn some regular

    expression ✤ Look into the standard “find” library ✤ When you’re ready for the really crazy stuff, look up Ruby’s BEGIN { … } and END { … } blocks
  54. One Last Warning ✤ Remember, I didn’t say these are

    the best ways to do things ✤ There are definitely shell commands that do some of these things better ✤ You can move on to learning those later ✤ Or you may already know them! ✤ That’s not the point ✤ The point: get new ideas and learn new things