Skip to content
shellhacks.dev
Python

Python vs Perl vs Ruby for Text Processing Scripts

Compare Python, Perl and Ruby for text processing scripts: one-liners, regex support, startup, availability on servers, and which to choose for new work.

6 min read
Summarize in AI
Illustration for "Python vs Perl vs Ruby for Text Processing Scripts": a shell script in an editor, a process monitor, a loop arrow.

All three can turn a messy log into a table, rewrite a file in place or extract fields with a regex. They differ in where they come preinstalled, how their one-liners feel and how readable a longer script is a year later. The versions relied on here are Perl 5.38, Python 3.12 and Ruby 3.3; the classic Unix tools they compete with are covered in Perl versus sed versus awk.

The same one-liner

Shell
perl -ne 'print "$1\n" if /status=(\d{3})/' access.log
ruby -ne 'puts $1 if /status=(\d{3})/' access.log
python3 -c 'import re,sys
for l in sys.stdin:
    m = re.search(r"status=(\d{3})", l)
    if m: print(m.group(1))' < access.log

Perl and Ruby have -n (loop over lines) and -p (loop and print) flags and the regex operator in the language, so the filter is a single short line. Python has no equivalent flags, so a one-liner needs a multi-line string or a small file, which is why it is rarely used for ad hoc filters. In-place editing is perl -pi -e 's/foo/bar/' file, with -pi.bak to keep a backup, and ruby -pi -e '...' works the same way; Python needs a script.

Availability

Perl is part of the base system on almost every Linux distribution and on macOS, because package managers and Git tools depend on it, though some minimal containers drop it. Python 3 is on most current distributions but not in every minimal image, and macOS no longer ships a usable one. Ruby is rarely preinstalled outside macOS. On a stripped container, none of the three may be present, and the answer is the shell tools in sed versus awk.

Readability and growth

Python
import re, sys, collections

counts = collections.Counter()
for line in sys.stdin:
    m = re.search(r'status=(\d{3})', line)
    if m:
        counts[m.group(1)] += 1
for status, n in counts.most_common():
    print(status, n)

As a script grows, Python's explicit style, standard library and tooling make it easier to maintain, and more people can read it. Perl's terseness, with implicit variables such as $_, is powerful in a one-liner and a burden in a hundred lines. Ruby sits between them: expressive, with strong string and enumerable methods, and a gem ecosystem, but a smaller operations community.

Regex features

Perl's regular expressions are the reference that PCRE copies, with named captures, lookaround, possessive quantifiers and the /x flag. Ruby uses the Onigmo engine with very similar syntax. Python's re module covers most of it, with some differences such as the lack of possessive quantifiers before 3.11 and no recursion, and the third-party regex module fills the gaps. The differences between engines are in regex differences across tools.

Where each language came from

The three languages grew up around different jobs, and the origin still shows. Perl was written to extract and report from text, and it keeps regular expressions, string interpolation and file handling as core syntax, with a huge archive of modules on CPAN. Ruby borrowed much of that text-processing power and added a consistent object model and a style many find pleasant to read, and it is the language behind a lot of infrastructure tooling such as Chef and Homebrew. Python aimed at readability and a broad standard library, and its ecosystem grew in every direction, from web services to data science, so a script that starts as a log filter can be extended into a service without a change of language. None of the three is the wrong choice; the question is which one your team can read at three in the morning.

Availability decides more projects than taste. A minimal container image may have none of them. A base server image usually has Perl because the package tools depend on it, and often Python 3 as well, since many system utilities now use it. On macOS, Perl and Ruby ship with the system, and Python 3 arrives with the developer tools. A script that has to run on machines you do not control should state its interpreter and minimum version, and check at the start.

Text processing in practice

For line-oriented work, Perl's one-liners are hard to beat. Flags such as -i for in-place editing, -a for auto-splitting each line into an array, and -F for the separator turn a transformation that needs a page of Python into a short command. Python's answer is the small script: a few lines with a loop, a regular expression and a print, which is more typing and easier to extend with a real argument parser, tests and logging. Ruby sits between them. For one-off commands typed in a terminal, Perl wins on brevity. For code that others will maintain, a Python script with functions and tests wins on clarity, and the difference grows with the length of the program.

Dependencies and packaging

Each language has a package ecosystem and a way to isolate it. Python uses virtual environments and pip, with the standard library covering JSON, CSV, HTTP, argument parsing, subprocesses and archives without installs. Perl uses CPAN clients and local::lib, and ships many core modules; Ruby uses gems and Bundler. The practical advice is the same for all three: use the standard library where possible, pin versions of what you add, and keep scripts that run unattended in a virtual environment with an explicit path to its interpreter. A script that imports a third-party module will fail on a machine where it is missing, and the failure appears at the worst time.

Performance and long-running work

For scripts that process files of a few hundred megabytes, all three are adequate if the code reads lazily, line by line. Perl's regex engine is highly tuned and often the fastest for heavy pattern work. Python's speed is fine for most glue, and for numerical work it hands off to compiled libraries. Ruby is comparable to Python for scripts. When performance becomes the problem, measure before rewriting: profile with cProfile in Python, Devel::NYTProf in Perl, or the stdlib profilers in Ruby, and look at disk use and algorithm choices before language choice. A quadratic loop is slow in any language.

Making a choice

If the team already uses one of them, use it. If you are starting from nothing, Python is the safest default because of its reach, its readable syntax and the number of people who know it. Keep Perl for the places where it is already installed and the job is a text transformation that fits in a one-liner. Choose Ruby when the surrounding tools are Ruby. And remember the fourth option: for glue that is mostly running commands and checking exit codes, a Bash script is often shorter than any of them.

Where this does not apply

For work that is mostly running programs, Bash is simpler than any of these, see Python versus Bash for DevOps scripts. Existing code decides a lot: do not rewrite a working Perl script because Perl is out of fashion, and do not start a new one in it if nobody on the team reads Perl. Check each language's documentation for details: perlrun for the command-line switches, Python's re module, and the Ruby documentation.

Share

Keep reading

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.