in

Ruby one-liners, Hacker News

Ruby one-liners, Hacker News


This is a translation of Eric Pement’scollection of Awk one-linersas Ruby one-liners. These so-calledone-linersare small programs that hold on a single (sometimes longish) line of code, so it may be run from the command line, typically for text processing purposes. So, all problems solved by Awk one-liners on the page linked above are solved here in Ruby, sorted along the same categories as Pement’s work. In some cases, multiple solutions are proposed, as they outline nice features or idiosyncrasies of the Ruby language and conventions.

Note that this is not the first collection of Ruby one-liners: googling “Ruby one-liner” yields multiple hits. However, I have put up this collection by myself, without looking at other solutions, for the sake of practice. I have posted about what generalities I have learned throughout this exercisehere.

Double-space a file.

ruby ​​-ne 'print; puts' ruby -ne 'BEGIN {$ =" n"}; print ' ruby -pe 'BEGIN {$ =" n"};'

Double-space only non-blank lines.

ruby ​​-ne 'print; puts unless $ _. chomp.empty? ' ruby -ne 'print; puts unless ~ / ^ $ / ' ruby -ne 'print $ _   ((~ / ^ $)? "": " n")'

Triple-space a file.

ruby ​​-ne 'print; 2.times {puts} ' ruby -pe 'BEGIN {$ =" n  n"};'

Precede each line by its file-specific line number (left-aligned). Using a tab instead of space will preserve margins.

ruby ​​-pe 'print $<. file.lineno t>

Precede each line by its overall line number, with tab.

ruby ​​-pe 'print $., " t"'

Number each line of a file (at left, right-aligned).

ruby ​​-ne 'printf "% 5d:% s", $., $ _'

Number non-blank lines.

ruby ​​-ne 'BEGIN {$ n=0}; if ~ / ^ $ /; print; else      $ n =1; printf "% 5d:% s", $ n, $ _; end '

Count lines (emulateswc -l).

ruby ​​-ne 'END {printf "% 8d% s  n", $., $ FILENAME}'

Print the sums of the fields of every line (expects fields to be integers).

ruby ​​-ane 'puts $ F.reduce (0) {| sum, x | sum   x.to_i} '

Print the sum of all integers present on all lines.

ruby ​​-ane 'BEGIN {$ sum=0}; $ sum =$ F.reduce (0) {| s, x | s   x.to_i};      END {puts $ sum} ' ruby -ane 'BEGIN {$ a=[]}; $ a =$ F.map {| x | x.to_i};      END {puts $ a.reduce (0) {| s, x | s   x}} ' ruby -e 'puts readlines.map {| r | r.split.map {| x | x.to_i}}. flatten      .reduce (0) {| s, x | s   x} '

Replace each integer field with its absolute value. All spacing is reduced to a single space.

ruby ​​-ane '$ F.map! {| x | x.to_i.abs}; puts $ F.join ("") '

Print the total number of words (fields) over all text. Word separators are any sequence of whitespace.

ruby ​​-ane 'BEGIN {$ t=0}; $ t =$ F.size; END {puts $ t} '

Print the total number of lines that contain “Beth”.

ruby ​​-ne 'BEGIN {$ t=0}; $ t =1 if ~ / Beth /; END {puts $ t} '

Print the largest first field and the line that contains it.

ruby ​​-ane 'BEGIN {$,=" t"; $ max=0; $ maxline=""};      $ n=$ F [0]. to_i; if $ n>$ max; $ max=$ n; $ maxline=$ _; end;      END {print $ max, $ maxline} ' ruby -e '$,=" t"; print readlines.map {| r | s=r.split; [s [0]. to_i, r]}      .max {| a, b | a [0]b [0]} '

Print the number of fields on each line, followed by the line.

ruby ​​-ane 'BEGIN {$,=" t"}; print $ F.size, $ _ ' ruby -ane 'printf "% 3d% s", $ F.size, $ _'

Print the last field of each line.

ruby ​​-ane 'puts $ F.last'

Print the last field of the last line. [Update 5-Dec-2011] The second, better solution was contributed by Florian Hanke (@hanke):

ruby ​​- ane '$ f=$ F.last; END {puts $ f} ' ruby -ane 'END {puts $ F.last}'

Print every line with more than 4 fields.

ruby ​​-ane 'print if $ F.size>4'

Print every line for which the value of the last field is>4.

ruby ​​-ane 'print if $ F.last.to_i>4'

Create a string of a specific length (eg generate (spaces).

ruby ​​-e 'puts "" * 513 '

Insert a string of specific length at a certain character position. For example, insert 49 spaces after column 6 of each input line.

ruby ​​-pe 'sub! /^.{6}/, "\ &"   "" * 49 '

The following are useful bits of Ruby code to easily make up arrays and hashes (associative arrays that may be indexed by any soft of object, yet often indexed by strings).

Create an array of token strings named $ month.

$ month=% w {Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec}

Create the reverse hashtable of the $ month array, which given the month index for the given month name.

$ mdigit={}; $ month.each_with_index {| m, i | $ mdigit [m]=i}

More generally, create a hash $ h that indexes the contents of array $ v with keys from array $ k of the same size.

$ h={}; $ k.zip ($ v) .each {| k, v | $ h [k]=v}

[Update 5-Dec-2011] A better solution was contributed by Florian Hanke (@hanke):

$ h=Hash [$k.zip($v)]

In a UNIX environment, convert DOS / Windows newlines (CR LF) to Unix (LF).

ruby ​​-pe 'sub! /  r  n $ /, " n" '

In a UNIX environment, convert Unix newlines (LF) to DOS / Windows (CR LF).

ruby ​​-pe 'BEGIN {$;=" r  n"}; chomp! '

In a Windows environment (forget DOS, I don’t care whether Ruby runs there), convert DOS / Windows newlines (CR LF) to Unix (LF).

ruby ​​-pe 'BEGIN {$;=" n"}; chomp! '

In a Windows environment, convert Unix newlines (LF) to DOS / Windows (CR LF).

ruby ​​-pe 'sub! /  n $ /, " r  n" '

Delete leading whitespace from the front of each line, thereby aligning all text flush left.

ruby ​​-pe 'sub! / ^  s * /, "" '

Delete trailing whitespace from the end of each line.

ruby ​​-pe 'sub! /  s * $ /, "" '

Delete both leading and trailing whitespace from each line.

ruby ​​-pe 'gsub! / ^  s * |  s * $ /, "" '

Insert 5 blank spaces at the beginning of each line.

ruby ​​-pe 'sub! / ^ /, "" * 5 '

Align all text flush right on a 79 – column width.

ruby ​​-ne 'printf "% 79 s ", $ _ '

Center all text on a 79 – character width.

ruby ​​-ne 'print "" * (79 - $ _. chomp.size) / 2), $ _ ' ruby -ne '$ l=$ _. chomp.size; if $ l>79; print;      else print "" * ((79 - $ l) / 2), $ _; end '

The first of these one-liners is a faithful Ruby translation of the equivalent Awk one-liner from Eric Pement’sawk1line.txt. The second takes into account the edge case by which a line could not be properly centered within 79 characters.

Substitute “foo” with “bar” one each line.

ruby -pe 'sub! / foo /, "bar" '# Only 1st instance. ruby -pe 'gsub! / foo /, "bar" '# All instances.

Substitute “foo” with “bar” only on lines that contain “baz”.

ruby ​​-pe 'gsub! / foo /, "bar" if ~ / baz / '

Substitute “foo” with “bar” except on lines that contain “baz”.

ruby ​​-pe 'gsub! / foo /, "bar" unless ~ / baz / '

Replace “scarlet” or “ruby” or “puce” with “red”.

ruby ​​-pe 'gsub! / scarlet | ruby ​​| puce /, "red" '

Reverse order of lines (emulatesTAC).

ruby ​​-e 'readlines.reverse.each {| r | print r} '

If a line ends with a backslash, append the next line to it, removing the backslash.

ruby ​​-pe 'while ~ / \ $ /; chomp; chop; $ _ =gets.to_s; end ' ruby -pe 'sub! / \ s *  n $ /, "" '

The first of these two one-liners is a rather faithful translation of Pement’s equivalent one-line. Contrary to the latter, this one does work with sequences of multiple backslash-ending lines. It even works with the edge case of having the last line terminated with a backslash. In this case,getsreturnsnil, which does not match the regular expression, thereby breaking the loop. A problem would however arise as thenilvalue cannot be concatenated to the current line: this is why we call methodto_sof whatevergetsreturns. If it is a string,to_sacts as identity; if it isnil, its string value is the empty string, yielding a non-breaking last output line.

The second one-liner is a much simpler solution to the problem that uses explicit line ending modifications to obtain merges between backslash-enders and other lines. This is more awkward to pull off in Awk (haha, its Awkward), since line ending is determined by the contents of variable ORS, the value of which persist between lines. It does still yield a shorter solution than the first equivalent Ruby one-liner, though

awk '{ORS="  n "} / \ $ / {sub (/ \ $ /," "); ORS=""} 1 '

Print and sort the login names of all users.

ruby ​​-F: -ane 'BEGIN {$ s=open ("| sort", "w")};      $ s.puts $ F [0] unless / ^ # /; END {$ s.close} '/ etc / passwd ruby -F: -ane '$ s.puts $ F [0] unless / ^ # /' / etc / passwd | sort ruby -e 'readlines.map {| r | r.split (":") [0]}. sort.each {| n | puts n} '/ etc / passwd

While longer, the last of these one-liners does not require the standard Unixsortutility.

Print the first 2 fields of every line in opposite order (spacing is normalized).

ruby ​​-ane 'BEGIN {$,=""; $ =" n"}; print $ F [1], $ F [0] ' ruby -ane 'puts $ F [0..1]. reverse.join ("")' ruby -ane 'puts $ F [0...2]. reverse.join ("")' ruby -ane 'printf "% s% s  n", $ F [1], $ F [0]'

Switch the first 2 fields of every line (spacing is normalized).

ruby ​​-ane '$ F [0], $ F [1]=$ F [1], $ F [0]; puts $ F.join ("") ' ruby -ane 'if $ F.size

The first version is a faithful translation of Pement’s equivalent Awk one-liner, while the second handles the case where lines may not all have at least two fields.

(Delete the second field off every line (spacing is normalized).

ruby ​​-ane 'BEGIN {$,=""; $ =" n"}; $ F.delete_at 1; print * $ F ' ruby -ane '$ F.delete_at 1; puts $ F.join ("") '

Print in reverse order the fields of each line (spacing is normalized).

ruby ​​-ane 'BEGIN {$,=""; $ =" n"}; print * $ F.reverse ' ruby -ane 'puts $ F.reverse.join ("")'

Concatenate every group of 5 lines of input, using a comma separator between concatenated lines.

ruby ​​-pe 'chomp; $ =($.% 5==0? " N": ",") ' ruby -pe 'chomp; $ =if $. % 5==0; " n"; else ","; end '

Print first 10 lines of file (emulates behavior of (head).

ruby ​​-pe 'exit if $.>10 ' ruby -ne 'print if $.

Print first line of file (emulateshead -1).

ruby ​​-pe 'exit if $.>1 '

Print the last two lines of a file (emulates (tail -2).

ruby ​​-ne 'BEGIN {$ tail=["",""]}; $ tail.shift; $ tail

This is very inefficient. Thetailutility does it much better.

Print the last line of a file (emulates (tail -1) )

ruby ​​-ne 'END {print}'

Print only lines that match some regular expression (emulatesgrep).

ruby ​​-ne 'print if ~ / regex /'

Print only lines that do NOT match some regular expression (emulates (grep -v).

ruby ​​-ne 'print unless ~ / regex /'

Print lines for which field # 5 is equal to “abc 123 ”.

ruby ​​-ane 'print if $ F [4]=="abc 123 ''

Print lines for which field # 5 is not equal to “abc 123 ”.

ruby ​​-ane 'print if $ F [4]!="abc 123 ''

Same as above, but avoid printing a line if it does not have at least five fields.

ruby ​​-ane 'print if $ F.size>=5 && $ F [4]!="abc 123 ''

Print lines for which the 7th field matches (respectively doesn’t match) a regular expression.

ruby ​​-ane 'print if $ F [6]=~ / ^ [a-f] / ' ruby -ane 'print unless $ F [6]=~ / ^ [a-f] /'

Print the line immediately before a regular expression, but not the line that matches it.

ruby ​​-ne 'print $ r.to_s if ~ / regex /; $ r=$ _ '

Print the line immediately after a regular expression, but not the line that matches it.

ruby ​​-ne 'while ~ / regex /; break unless gets; print; end ' ruby -ne 'while ~ / regex /; gets; print $ _. to_s; end '

Grep for AAA, BBB and CCC in any order on the same line.

ruby ​​-ne 'print if ~ / AAA / && ~ / BBB / && ~ / CCC /'

Grep for AAA, BBB, and CCC in this order.

ruby ​​-ne 'print if ~ / AAA. * BBB. * CCC /'

Print only lines of 65 characters or longer.

ruby ​​-ne 'print if $ _. size>64 '

Print only lines shorter than 65 characters.

ruby ​​-ne 'print if $ _. size

Print section of file from regular expression to end of file.

ruby ​​-ne 'print $ _, * readlines if ~ / regex /'

Print section of file comprised between numbered lines (eg lines 8 – 12, inclusive).

ruby ​​-ne 'print if (8 .. 12)===$. ' ruby -ne 'print if (8 .. 12). include? ($.) '

Print line 52.

ruby ​​-ne 'print if $.==52 '

Print section of file between two regular expressions (inclusive).

ruby ​​-ne 'if $ in; print; $ in=! (~ / Montana /); else;      $ in=~ / Iowa /; print if $ in; end '

Delete all blank lines from a file (same asgrep '.').

ruby ​​-ne 'print unless ~ / ^ $ /' ruby -ne 'print if ~ /./' ruby -ne 'print if $ _. chomp.size>0'

Remove consecutive duplicate lines (emulatesuniq).

ruby ​​-ne 'print if $ _!=$ prev; $ prev=$ _ '

Remove nonconsecutive duplicate lines.

ruby ​​-ne 'BEGIN {$ h={}}; print unless $ h [$_]; $ h [$_]=$ _ ' ruby -e 'print * readlines.uniq'

Brave Browser
Read More
Payeer

What do you think?

Leave a Reply

Your email address will not be published. Required fields are marked *

GIPHY App Key not set. Please check settings

Dow Jones Stock Spooks Investors & It Could Be a Robot's Fault – CCN.com, Crypto Coins News

Dow Jones Stock Spooks Investors & It Could Be a Robot's Fault – CCN.com, Crypto Coins News

New iPhone 11 Pro video ads focus on toughness, triple rear cameras – GSMArena.com news – GSMArena.com, Gsmarena.com

New iPhone 11 Pro video ads focus on toughness, triple rear cameras – GSMArena.com news – GSMArena.com, Gsmarena.com