perl.gg / one-liners

Bash One-liners

2024-07-09

PERL ONE-LINERS IN BASH SCRIPTS

Sometimes you want the best of both worlds. Bash is great for orchestrating system tasks, but Perl brings that extra punch when you need text processing, colorful output, and proper error handling all rolled into one elegant line.

Today we are looking at a pattern I use all the time: feeding shell commands through a Perl one-liner that executes them with style.

Part 1: THE HEREDOC SETUP

First, we need to collect our commands. Bash heredocs are perfect for this. The quoted delimiter prevents variable expansion, keeping our commands pure:
read -r -d '' CMDS <<'CMDS' sudo apt install -y build-essential sudo cpanm JSON::XS CMDS
The -r flag prevents backslash interpretation, and -d '' reads until EOF. Now $CMDS holds our multi-line command list, ready for processing.

Part 2: THE PERL ONE-LINER ANATOMY

Here is where the magic happens:
echo $CMDS | perl -MTerm::ANSIColor=':constants' -nlE ' chomp; unless ( m~^$|^\#~ ) { say BOLD GREEN qq|> $_|, RESET; system $_; unless ($? == 0) { die BOLD RED qq|> Fail: $?\n|, RESET; } } '
Let us break down those flags because they are the secret sauce:
-n Wraps your code in a while(<>) loop, processing line by line -l Handles line endings automatically (chomp on input, newline on print) -E Enables modern features like say() - think of it as -e with benefits -M Loads modules, here importing ANSI color constants

Part 3: WHAT THE SCRIPT ACTUALLY DOES

Walking through the logic:
chomp;
Strips the trailing newline. With -l this is somewhat redundant, but being explicit never hurts and makes the intent crystal clear.
unless ( m~^$|^\#~ ) {
Skip empty lines and comments. The tilde delimiters let us use slashes freely inside the regex. This is the kind of thoughtful touch that makes Perl one-liners maintainable.
say BOLD GREEN qq|> $_|, RESET;
Print the command we are about to run in bold green. The qq|...| quoting style avoids escaping issues. Visual feedback matters when running system commands - you want to see what is happening.
system $_;
Execute the command. This is the whole point. Perl's system() hands off to the shell and waits for completion.
unless ($? == 0) { die BOLD RED qq|> Fail: $?\n|, RESET; }
Check the exit status. If anything goes wrong, die in bold red with the actual exit code. No silent failures here.

Part 4: WHY THIS PATTERN WORKS

You might ask: why not just run the commands directly in bash? A few reasons:
  1. Unified error handling - one place to catch and report failures
  2. Consistent formatting - every command gets the same visual treatment
  3. Filtering logic - easy to skip comments, blank lines, or add conditions
  4. The -n loop - scales to any number of commands without extra scaffolding

This is the Perl philosophy in action: make the common case elegant and the complex case possible.

Part 5: VARIATIONS TO TRY

Dry run mode - just show what would execute:
echo $CMDS | perl -nlE 'say "Would run: $_" unless /^$|^#/'
Add timing information:
echo $CMDS | perl -MTime::HiRes=time -nlE ' next if /^$|^#/; my $start = time; system $_; printf "Took %.2fs\n", time - $start; '
Log to a file while also printing:
echo $CMDS | perl -nlE ' next if /^$|^#/; say $_; open my $log, ">>", "commands.log"; say $log scalar(localtime) . ": $_"; system $_; '
CLOSING THOUGHTS

The combination of bash's process control and Perl's text processing creates something greater than either alone. This heredoc-to-one-liner pattern has saved me countless hours when setting up new systems or running maintenance scripts.

The flags -nlE with -M for modules will cover 90% of your one-liner needs. Commit them to muscle memory and you will reach for this technique often.

Created By: Wildcard Wizard. Copyright 2026