Let's say I know I want to do something, but I can'd find a reliable predictable way to do with with bash utilities. I happen to also know some ruby code that would do exactly what I want. I could write a ruby script to read in from a file and process and then output, but thats a lot of hassle for a task so small. Luckily, ruby makes it very easy for us to easily pipe text into the ruby interpreter and provide ruby code to do whatever we want with that input.
For example:
$ echo "proper name" | ruby -ne 'puts $_.capitalize' Proper name
Or a bit convoluted with bash for loops:
$ for i in bob bill joe sam; do ruby -e "puts \"$i\".capitalize"; done Bob Bill Joe Sam
The -n argument:
-n Causes Ruby to assume the following loop around your script, which makes it iterate over file name arguments somewhat like sed -n or awk. while gets ... end
The -e argument:
-e command Specifies script from command-line while telling Ruby not to search the rest of the arguments for a script file name.
Which is a little confusing but basically means "run ruby code provided as argument"
Thats nice, but what if I need to use a method provided by a gem thats not included in the standard ruby library? as easy as:
$ cat > names.txt bob sally sam joe jack $ cat names.txt | ruby -r 'rbkb' -ne 'puts $_.capitalize.b64' Qm9iCg== U2FsbHkK U2FtCg== Sm9lCg== SmFjawo=
The -r argument:
-r library Causes Ruby to load the library using require. It is useful when using -n or -p.
Lastly, the -p argument can be of some use as well:
-p Acts mostly same as -n switch, but print the value of variable $_ at the each end of the loop. For example: % echo matz | ruby -p -e '$_.tr! "a-z", "A-Z"' MATZ
Another example:
$ cat names.txt | ruby -r 'rbkb' -n -e 'i = $_.chomp; puts i + " in base64 is: " + i.b64' bob in base64 is: Ym9i sally in base64 is: c2FsbHk= sam in base64 is: c2Ft joe in base64 is: am9l jack in base64 is: amFjaw==
You can use -p instead of -n with a puts but things can get weird (does print at end of loop instead of puts):
$ cat names.txt | ruby -r 'rbkb' -p -e '$_ = $_.capitalize.b64' Qm9iCg==U2FsbHkKU2FtCg==Sm9lCg==SmFjawo=
You can even technically paste in scripts and have them run:
cat names.txt | ruby -r 'rbkb' -ne ' > input = $_.chomp > puts "The current input being processed is: \"#{input}\"" > puts "The current time is: #{Time.now}" > puts "The Base64 encoded value of #{input} is #{input.b64}" > ' The current input being processed is: "bob" The current time is: 2016-03-03 12:15:10 -0600 The Base64 encoded value of bob is Ym9i The current input being processed is: "sally" The current time is: 2016-03-03 12:15:10 -0600 The Base64 encoded value of sally is c2FsbHk= The current input being processed is: "sam" The current time is: 2016-03-03 12:15:10 -0600 The Base64 encoded value of sam is c2Ft The current input being processed is: "joe" The current time is: 2016-03-03 12:15:10 -0600 The Base64 encoded value of joe is am9l The current input being processed is: "jack" The current time is: 2016-03-03 12:15:10 -0600 The Base64 encoded value of jack is amFjaw==
Just be careful with escaping your quotes:
$ cat names.txt | ruby -r 'rbkb' -ne ' > puts $_.chomp + 'asdf' > ' -e:2:in `<main>': undefined local variable or method `asdf' for main:Object (NameError)
Even if you try to escape the single quotes (Bash doesnt read it the way you think it should):
$ cat names.txt | ruby -ne ' > puts $_.chomp + \'asdf\' -e:2: syntax error, unexpected $undefined puts $_.chomp + \asdf' ^ -e:2: unterminated string meets end of file $ echo '\'' >
You'd have to use the Bash syntax ANSI strings (note the $ before the opening single quote):
$ cat names.txt | ruby -ne $' > puts $_.chomp + \'asdf\' > ' bobasdf sallyasdf samasdf joeasdf jackasdf
Lot's of caveats and gotcha's to consider, know, and think about. Remember, pipe to ruby when it's simple and convenient. If you start getting too complicated with multiple lines and quote escapes, just put it in a file and run that instead.
No comments:
Post a Comment