Hello ladies and gentlemen! I'm happy to announce my 3rd e-book called "Perl One-Liners Explained." This book is based on the "Famous Perl One-Liners Explained" article series that I wrote over the last 3 years and that has been read over 500,000 times!

I went through all the one-liners in the article series, improved explanations, fixed mistakes and typos, added a bunch of new one-liners, added an introduction to Perl one-liners and a new chapter on Perl's special variables.

Table of Contents

The e-book has 111 pages and it explains 130 unique one-liners. Many of one-liners are presented in several different ways so the total number of one-liners in the book is over 200.

The e-book is divided into the following chapters:

  • Preface.
  • 1. Introduction to Perl One-Liners.
  • 2. Spacing.
  • 3. Numbering.
  • 4. Calculations
  • 5. String Creation and Array Creation.
  • 6. Text Conversion and Substitution.
  • 7. Selective Printing and Deleting of Lines.
  • 8. Handy Regular Expressions.
  • 9. perl1line.txt
  • Appendix A. Perl's Special Variables.
  • Index.

What are Perl One-Liners?

Perl one-liners are small and awesome Perl programs that fit in a single line of code and they do one thing really well. These things include changing line spacing, numbering lines, doing calculations, converting and substituting text, deleting and printing certain lines, parsing logs, editing files in-place, doing statistics, carrying out system administration tasks, updating a bunch of files at once, and many more.

Let's take a look at several practical examples that you can easily do with one-liners. All these examples and many more are explained in the e-book.

I have also made the first chapter of the book, Introduction to Perl One-Liners, freely available. Please download the e-book preview to read it.

Example 1: Replace a string in multiple files at once

perl -p -i.bak -e 's/Config/config/g' conf1 conf2 conf3

Suppose you have 3 configuration files, and you discover that you made a mistake and need to replace all occurrences of Config with config. This one-liner does just that. It executes the s/Config/config/g that replaces all occurrences of Config with config on all lines. And since you're smart about it, you always do -i.bak to make backup files in case something goes wrong.

I explain the -i, -p, and -e arguments in the e-book in great detail.

Example 2: Generate a random 8 character password

perl -le 'print map { ("a".."z")[rand 26] } 1..8'

This one-liner generates and prints a random 8 character password. It uses the list range operator .. operator to produce all strings from "a" to "z", which is the alphabet. Then a random letter is chosen by rand 26 and this operation is repeated 8 times.

Example 3: URL-escape a string

perl -MURI::Escape -lne 'print uri_escape($string)'

Here we use the URI::Escape module from CPAN. It exports the uri_escape function that does URL-escaping.

You can install this module from CPAN by running perl -MCPAN -e'install URI::Escape' on the command line.

I have this one-liner as an alias actually for both URL-escaping and unescaping URL-escaping as it's such a common thing to do:

urlescape () { perl -MURI::Escape -lne 'print uri_escape($_)' <<< "$1" }
urlunescape () { perl -MURI::Escape -lne 'print uri_unescape($_)' <<< "$1"; }

Then I can do this in the shell:

$ urlescape "http://www.catonmat.net"

$ urlunescape http%3A%2F%2Fwww.catonmat.net

Very useful!

Example 4: Print all lines from line 17 to line 30

perl -ne 'print if 17..30'

Here we use the binary flip-flop operator .. that becomes true when the input line number is 17, stays true while the line number is less than or equal to 30, and then becomes false. Combining the flip-flop operator with print if makes it print only lines 17-30.

Example 5: Remove all consecutive blank lines, leaving just one

perl -00pe0

I included this one-liner here in the examples just to show you how funny and obscure one-liners can get. This one-liner deletes all repeated blank lines from the input or from the given file. It does it by enabling the paragraph slurp mode through -00 command line argument, which reads the input paragraph-by-paragraph, rather than line-by-line, and prints the paragraphs. This way any number of blank lines between the paragraphs get ignored.

I explain this one-liner in more details in the e-book.

As I hope you can see, knowing how to write one-liners is very useful. It was one of my top priority tasks through the years to become very efficient in the shell. Literally every day when I'm programming, I have to do all kinds of data processing tasks, changing files, verifying output, doing quick calculations, parsing data, etc, and knowing Perl one-liners makes it really fast to get things done.

Now that I have written this e-book, you can become very efficient, too. Enjoy!

Book Preview

I prepared a free book preview that contains the first 13 pages of the book. It includes the table of contents, preface, introduction to Perl one-liners and the first page of the second chapter.

Buy it now!

The price of the e-book is $9.95 and it can be purchased via PayPal:

PayPal - The safer, easier way to pay online!

After you have made the payment, my automated e-book processing system will send you the PDF e-book in a few minutes!

Tweet about my book!

Help me spread the word about my new book! I prepared a special link that you can use to tweet about it:

What's next?

I really love writing about programming and I have planned writing many more books. The next few are going to be a book on mastering vim, a practical guide on how to be anonymous on the web, and the catonmat book.


Enjoy the book and don't forget to leave comments about it! Ask me anything you wish and I'll help you out.

Also if you're interested, take a look at my other two e-books. The 1st one is called "Awk One-Liners Explained" and the 2nd one is called "Sed One-Liners Explained" They're written in a similar style as this e-book and they teach practical Awk and Sed through many examples.

Finally, if you enjoy my writing, you can subscribe to my blog, follow me on Twitter or Google+.


Zsolt Botykai Permalink
February 01, 2012, 16:20

I will buy it as soon as it will be available in a format I can read on my Kindle (no I will not read PDFs ever on it).

February 01, 2012, 16:47

Hi Zsolt,

Now that I finished the trilogy of awk, sed, and perl e-books, I will finally finish the parser to convert them to .mobi and .epub.

Sorry for the delay!

Mark Cooper Permalink
May 08, 2012, 01:50

When they're available is it buy once and get all the formats?

Svetlana W Permalink
June 25, 2014, 23:26

hmm... saw the book on Amazon but decided to buy from here thinking that direct sale is better for the author, and assuming that Kindle version will be part of a bundle... The book arrived by email in PDF format only... i guess i jumped the gun...? So.. do i have to pay again to Amazon to get it in the format I actually need?

February 02, 2012, 02:15

Just in case you use this phrase in your ebook, too, "Suppose you have 3 configuration files, and you discover that you made a mistake and need to replace all occurrences of Config to config." requires 'with', not 'to': "[...] all occurrences of Config with config."

February 02, 2012, 05:34

Thanks for correcting! I don't think I use it in the book but I will check. Fixed in the article.

Marco Bodemeijer Permalink
January 28, 2013, 11:10

Example 2: Generate a random 8 character password

In most environments the passwords have to consist of 6 characters with at least 1 capital and ending with 2 numbers (e.g. abCdef12). Is there a one-liner for that too?

January 30, 2013, 23:39


perl -le 'print @{[map { ("a".."z", "A".."Z")[rand 52] } 1..6]}, int rand 10, int rand 10'
Stuart Permalink
February 16, 2013, 06:03

Great book! Question: How would I create a one liner to print all lines in a text file that DON'T contain the word "water" unless the line also contains the word "plants"? Using this in a Win 7 environment.

February 24, 2013, 18:44

Hi Stuart! Here's how:

perl -nle "print if !/water/ || /plants/"

This basically says - print the line if it doesn't contain water. But if it contains water, print it only if it contains plants.

Stuart Marmorstein Permalink
February 25, 2013, 02:40

Works like a charm! Many thanks

Stuart Marmorstein Permalink
February 26, 2013, 19:28

I use some tilde-delimited .txt and .ini files as searchable databases. Running Win 7 32-bit. Perl may work faster than some routines I am currently using. If I want to work with a record in a file that looks like this:

ADVJSMF=Last~Familiar Name~First Name~Salutation~Street Address~City~State~zipcode~email address~work number~home number~etc. and I wanted to use a one-liner to retrieve info only in one field or manipulate only one field (for instance the email field) based on the identifier to the left of the equal sign, is there a way to do that? If so, I'd love to know how to do that.

In a similar database containing records, I also perform searches to find out whether someone has a birthday that falls within a few days of the search date I am using, but I could save that question for another time. Many thanks! Stuart

March 26, 2013, 16:45

Hi Stuart!

It's definitely possible to do that. Here's the basic idea. First you'd split the line into left and right, and then split the right part into fields:

perl -nle "
 my ($left, $right) = split '=', $_, 2;
 my @fields = split '~', $right;

Now you just have to test if $left is something that you're looking for, for example, if it is "ADVJSMF":

perl -nle "
 my ($left, $right) = split '=', $_, 2;
 my @fields = split '~', $right;
 if ($left eq 'ADVJSMF') {
   # do something

Now just replace # do something with the actual thing to do. For example, to print First Name, you'd print $fields[2]:

perl -nle "
 my ($left, $right) = split '=', $_, 2;
 my @fields = split '~', $right;
 if ($left eq 'ADVJSMF') {
   print $fields[2];

Modifying fields is a bit trickier as it involves re-assembling the fields, left part and right part.

But here's how you'd do it:

perl -nle "
 my ($left, $right) = split '=', $_, 2;
 my @fields = split '~', $right;
 if ($left eq 'ADVJSMF') {
   $fields[2] = 'New First Name';
 my $new_fields = join '~', @fields;
 print $left, '=', $new_fields;

This modifies the First Name, and then prints the updated line.

April 11, 2013, 03:00

Hi Peteris,

Since I had many .ini files to search, I used the following strategy from the Win 7 command line to combine a bunch of them into one:

type ?.ini > all.log

My next question is, can Perl in Win 7 handle anything like wildcard symbols ? and * to search across many ASCI .txt, .ini, etc. files in one shot?


April 11, 2013, 02:50

This code has taught me a lot. It works for reading or modifying fields, and it's FAST! Thank you so much!

April 12, 2013, 17:16

Hi Peteris,

I was able to get the file match thing to work with no problem.

I had trouble with getting the BEGIN block to work. Didn't know what to do with quotes, semicolons, braces in the area shown as ... your original perl code goes here ... before the second double quote. Could you give me an example of matching a string or replacing a string using the BEGIN block and the @ARGV array in Win 7?

I tried a few things on my own, but didn't get anywhere with this, and have a feeling that this is an important concept for me to get.

Will post on blog. Thank you, again--Stuart

April 29, 2013, 01:21

hi Peteris,

Thanks to you, I can get many tasks done requiring searches through groups of files using wildcards as in:

perl -pi.bak -e "BEGIN{@ARGV=<*.ini>} /77345/ && s/Humble/Kingwood/"

which changes the name of the town, Humble, to Kingwood in a group of .ini files if the zip code is 77345.

Next question for a practical application:

I use a command line program in Win 7 called getmail, which downloads emails from one of my accounts and saves them as .txt files in the form msg*.txt.

I would like to have a Perl one-liner that can read through these files looking for certain text strings that would identify them to me as SPAM.

How could I get a one-liner to take the FILENAME of the offending file and write it to a line in another text file that I could use to delete SPAM emails?

I have done something similar with sgrep, and it seemed to work for a while, but lately some inconsistent results are cropping up.

All the best--Stuart

May 08, 2013, 17:39

Hi Stuart,

I've been busy so forgive me my late reply.

You can solve this problem with a Perl one-liner but it gets a bit complicated. It's best if you moved to writing Perl programs at this point rather than one-liners.

Does each email gets saved as a separate msg*.txt file? If so you can do the following:

perl -e "
  my @files = <msg*.txt>;
  open my $out, '>', 'spam-emails.txt' or die 'failed opening spam-emails.txt: ' . $!;

  for my $file (@files) {
    my $contents = do {
      open my $fh, '<', $file or die 'error opening ' . $filename . ': ' . $!;
      local $/; <$fh>
    $_ = $contents;
    if (/spam_keyword_1/ && /spam_keyword_2/ && /spam_keyword_3/) {
      print $out qq/$file\n/;

What happens here is that we first setup @files array to contain the filenames of all emails in msg*.txt files.
Then we open the 'spam-emails.txt' file that will contain the list of filenames that are spam emails.
Next we loop over the filenames and read the contents of each email into $contents variable.
Then we check if the contents matches spam_keyword_1, spam_keyword_2, spam_keyword_3, and if so we print the filename of the spam email to spam-emails.txt.

You can create your own list of spam_keywords.

May 15, 2013, 22:20

A regex question for making this practical: I receive these message files when I use my getmail program to check mail from contact@drstuart.net. Some of my spam is written to other @drstuart.net addresses besides contact. Anything like that WOULD be spam. How would I make one of my spam_keyword entries be "other-than-contact"@drstuart.net?

Thanks! Stuart

May 22, 2013, 19:37

Hi Stuart,

Here's how you make one of your spam_keyword entries be "other-than-contact"@drstuart.net.

use warnings;
use strict;

my @files = <msg*.txt>;
open my $out, '>', 'spam-emails.txt' or die 'failed opening spam-emails.txt: ' . $!;

for my $file (@files) {
  my $contents = do {
    open my $fh, '<', $file or die 'error opening ' . $filename . ': ' . $!;
    local $/; <$fh>
  $_ = $contents;
  unless (/contact@drstuart.net/) {
    print $out qq/$file\n/;
  if (/spam_keyword_1/ || /spam_keyword_2/ || /spam_keyword_3/) {
    print $out qq/$file\n/;

Make sure that contact@drstuart.net is in the email when doing this.

What the "unless" line does is it checks if contact@drstuart.net is NOT the email, and if it is NOT, then print it to spam file, and proceed the next email. ("unless (x) { ... }" means "if (!x) { ... }" in Perl).

joe Permalink
August 20, 2013, 12:16


How to do get list users whose login Succeeded?
I been using i.e cat xcess.log | grep 2013-08-20|grep Succeeded| wc -l but if they refresh or logon again it's counted again

I tried diff combination of uniq but didn't work.

Leave a new comment

(why do I need your e-mail?)

(Your twitter name, if you have one. (I'm @pkrumins, btw.))

Type the word "browser_303": (just to make sure you're a human)

Please preview the comment before submitting to make sure it's OK.