Hacker News new | past | comments | ask | show | jobs | submit login
Ruby One-Liners (benoithamelin.tumblr.com)
110 points by kawera 33 days ago | hide | past | web | favorite | 48 comments



I knew Ruby copied a lot from Perl, but I wasn't prepared for just how much these are exactly how you would do the same thing in perl, just with the the order of passing lists reversed.

The command line switches are the same, the BEGIN/END block stuff is the same, the $F auto-splitting is the same.

Good on Ruby, that's the stuff that makes Perl one-liners actually worth coming back to again and again.


That kind of Ruby is pretty different from the Ruby one use to write applications like Rails. For example, after 14 years of Ruby I have no idea of what $F is. I have to google it, and I did at least 10 years of Perl before that.

I use Ruby for text processing now, because it's easier to read than Perl, but I loop on stdin with IO.readlines, each and split. It could be less efficient but I'm not parsing billions of records. I value readability more than one liners.


> That kind of Ruby is pretty different from the Ruby one use to write applications like Rails.

That's fair. That kind of Perl is also very different than the kind of Perl you would use to write Mojolicious applications, or system utils, or daemons. Those features are very specifically for quick one-liners[1], and in some cases don't even make sense outside of that.

> I use Ruby for text processing now, because it's easier to read than Perl, but I loop on stdin with IO.readlines, each and split.

In a one-liner, or as a small source file? Doing that in a small source file is also common in Perl, but if you're doing that as a one-liner, I think you're not making it more readable, you're making it less so, as the executable/language specifically support features to make that easier to do which you're ignoring, obfuscating the important parts of the code with verbose obvious bits. It's sort of like making sure to spell out et cetera instead of using etc even when texting or using Twitter.

1: BEGIN actually has some important uses in Perl, but under the covers for most people, so they never have to deal with it.


Small source files. I don't write one liners, they are hard to maintain.


Well, I don't write one-liners that are meant to be maintained either, but I don't put my piped commands of grep, but, sort and uniq into small source files either. They're meant for different things. There is conceivably a case for small one-off programs just like a chained shell statement, and that's what a one-liner is for.

For a really simple case, leveraging a module in the language to do the heavy lifting and do something per line. If I want robust CSV conversion for a TSV, loading up a CSV module in Perl or Ruby and letting it act on each line (after appropriately split on tab, and with the newline removed from each line, both a single command line switch away) is a very small one liner that's appropriately leveraging the language to do something that's hard with common shell utils.

There's a whole world of ways to leverage a powerful ecosystem with the built in one-liner features of Perl and Ruby. If you don't often find yourself doing a lot in the shell, then I can understand having a hard time imagining a case where it's not always better for a small source file, but for anyone whose responsibilities also entail a fair amount of system administration tasks, it can be extremely helpful.

If for nothing else, the number of times I've used autosplit or a nice regex to parse a complex line into an appropriate SQL statement I can output to another file, check, and then run is quite large. These often amount to a single regex and print per line, and are on some other log portion I've already grepped out, so generating the boilerplate for the line looping is actually more code than the actual statements that need to run. Add to that the times that there's no maintenance needed because the scripts are used to fix a one-off problem, and there are specific use cases where one-liners make sense. For a lot of people's workload, that might not be the case, but I definitely see the cases where it is.


What is that BEGIN{...} and END{...} syntax? I've seen a good amount of Ruby, but haven't encountered that yet.


It's basically there to make Ruby an equivalent to AWK. It only makes sense if you are looping over the lines with -n. The BEGIN block runs at the start of the run, and the END block at the end. They are useful for things like initializing a sum variable to zero at the start and printing it out at the end.


It's from awk: the BEGIN and END patterns match the start and end of a file/stream being processed, while normal patterns are checked on each line (and no pattern matches every line).

This is very useful to script a setup -> for reach line -> summary of a file e.g. initialise a map in BEGIN, fill the map for each line, and print the map in END.


What really baked my noodle is that there is another "end" called __END__ used like this

  $ cat data.rb 
  DATA.each_line { |ln|puts ln }

  __END__
  fish
  cat
  dog

  $ ruby data.rb 
  fish
  cat
  dog


I don't trust Ruby for text processing anymore.

The removal of the flip-flop operator, which is a fundamental tool in text processing, sent a very clear signal about the Ruby direction (that is, to be "The Rails language" and nothing else).

How can one be sure now, that all the functionality you've mentioned (and more) won't be removed as well?

Perl can be ugly, but its foundation in text processing are established.


> The removal of the flip-flop operator

Well that never happened. It was deprecated with the intention to remove it, but they backtracked: https://bugs.ruby-lang.org/issues/5400#note-25


I'm glad Ruby takes community feedback seriously, for the most part - most recently the pipeline operator and the named block parameters, for instance.


I heard Matz is going to remove the Perl special variables in Ruby 3.0. Can't think what the fuss is all about. They're pretty useful in command-line Ruby. I moved from Perl to Ruby so I will be sad to see this bit of Perl heritage removed from Ruby. I mean for what gain?


Only a very small subset of them: https://bugs.ruby-lang.org/issues/14240

    $/    input record separator (default argument for "gets")
    $\    output record separator ("print" prints it at last)
    $,    default separator for Array#join and print
    $;    default separator for String#split
As for the gain it's because these variables globally change the behavior of important core methods. They really aren't that useful, but can easily cause havoc.


Interesting. The discussion, although minimal, lasted years, then closed pretty quickly. Good for Ruby :-)


If you're going to write unreadable code why not use Perl? It's much faster than Ruby. Or Awk, even though it's one of the worst programming languages ever created?


Why is awk one of the "worst programming languages ever created"?


.. because you know Ruby and not Perl of course.

Ruby (and Perl) can and probably should be used for many tasks where you might use awk and sed and don't particularly care about performance.


One liners are not necessarily part of a codebase; one might use them for text processing on the fly.

An argument "against readability" is culture. For sysadmins, Perl is a well-known language; it's not unreadable¹. Note that the same applies to Bash, and Bash scripts are still popular. This doesn't imply that Perl/Bash scripts should be universally used, but that within a certain culture, they make perfect sense.

¹=when talking about oneliners


That's what I was thinking. Free to use Ruby any way you want, but this is not code I would be happy to see in my codebase.


What about getting some Obfuscated Ruby one-liners, like the well known Perl Obfuscation Contests? https://www.foo.be/docs/tpj/issues/vol4_3/tpj0403-0017.html :)


I think the natural successor to IOCCC and the Obfuscated Perl Contest is the Code Golf^1 community on stack exchange

^1: https://codegolf.stackexchange.com/questions?tab=Votes


I made a compilation of Ruby one-liners [1] as well last year.

There's plenty of stuff that is similar to Perl, which in turn had borrowed from awk, sed and other tools. The biggest difference I'd pick is Perl's context based operation.

    # Ruby requires explicit conversion with to_i
    ruby -ane 'print if $F[1].to_i > 35'
    perl -ane 'print if $F[1] > 35'
Performance is slower compared to Perl, but to those who already know Ruby, this would suit better than learning the nuances of another language.

[1] https://github.com/learnbyexample/Command-line-text-processi...


There are other significant other functionalities that I find very handy in oneliners, notably:

- automatic associative array instantiation

- the return value of regular expressions with a capture group is the value matched by it (in Ruby, the closest to this is `[/regex/, <group_i>]`)


I can't stand weak types, so I prefer Ruby even if it is a little longer. Thanks for pointing this out.


I always liked this one I wrote ages ago, to generate strong (at the time) passwords:

[code lang=“ruby”]

((33..126).map { |i| i.chr }).to_a.shuffle[0..14].join

[/code]


A bit more efficient:

14.times.map { rand(33..126).chr }.shuffle.join


Why shuffle? Does it do something rand doesn't already do?

At any rate, would probably want to use https://ruby-doc.org/stdlib-2.5.1/libdoc/securerandom/rdoc/S... for password generation.

Also, I think you might just want an alphabet and use sample: https://ruby-doc.org/core-2.5.1/Array.html#method-i-sample

# unsure if you need a:

require 'securerandom'

(33..126).sample(14, random: SecureRandom).map(&:chr).join


You're right, probably doesn't need shuffle :)


And 3x more possibilities because it allows the same character more than once. But I think the last shuffle is not necessary


Thanks! Learned something new today (even though I’m mostly on Python now)


Or for readable/memorable ones

    File.readlines('/usr/share/dict/words').map(&:strip).shuffle.first(5).map(&:capitalize).join

    => "PanChloroformateParoticTillotBrushoff"


OT: on mobile the authors bio fills up the entire screen. The headline is beneath the fold.


  1.upto(100){|n|puts'FizzBuzz'[i=n**4%-15,i+13]||n}


Maybe I'm being pedantic, but half of these use ";" to separate statements so I wouldn't really call them one liners.


A one liner does not mean "one line of source code in a file", it means "a single shell statement". That's why the Ruby command is prefixing them all. I routinely write 10-20 statement Perl one-liners at work for one off things.

For example, just yesterday it was to parse a log, grep for specific lines, pull out a time and a number per line, display name, number, and some number of characters afterwards as a quick abnd dirty graph of the magnitude to make it obvious if there were major outliers and to try to see trends over time. Still a one-liner.


In theory, couldn’t you then compile a Rails app into a one-liner? (Seems the max line length varies, but is at least hundreds of thousands of characters in most OSes)


You could, but it would be stupid to do so if it wasn't a trivial app, since nobody wants to support something like that, even if it's lifetime is measured in minutes or hours. It's a one-liner, just a pointless one.

That said, if rails has a super simple default startup that could serve a file, then it might be useful to start that as a one liner in select circumstances.


Rails has generators for that. Invaluable for greenfielding projects in an iterative manner. Blow everything away and recreate with a single command.

https://guides.rubyonrails.org/generators.html


nobody wants to support weird looking one-liners either


Sure, but then you could refactor most programs into "one line" (similar to what another commenter pointed out). I was expecting more of a functional piping or chaining style as opposed to distinct statements and defining local variables.


You're not being pedantic. The term "one-liner" is a misnomer. In many languages, whether or not a program can fit on a single line is a pointless metric, since a program can be rewritten into a single line (e.g. with semicolons or commas). People use the term "one-liner" as if it meant "concise code" which isn't necessarily true. It would be more accurate to just say "concise code".


I would expand on that and say 'concise code executed by directly invoking the parser in a shell-like environment using special flags such as a,n,p and e.'


Guess you could replace ; with && for many of them. More typing though.


This is what I love Ruby for: one-liners! :) Thanks for the summary, truly helpful.


I would never be able keep straight the escaping for these incantations. Writing code at the shell is not fun.


Not really an issue unless the one liner itself has single quotes in it, or perhaps you're using Windows?


I like to build lots of cool command-line one-liners in Python with the Mario tool.

https://github.com/python-mario/mario




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: