◈ Netsurfer / perl.gg / Bash One-liners

Bash One-liners

2024-07-09

PERL ONE-LINERS IN BASH SCRIPTS

This page shows how to run a list of shell commands through a Perl one-liner so you get clean error handling and colored output. Bash handles the orchestration, while Perl adds text processing and reliable error reporting in a single line.

I use this pattern whenever I need to execute a batch of system commands with clear visual feedback. The trick is feeding a shell variable into a Perl one-liner that runs each command and reports the result.

Part 1: THE HEREDOC SETUP

The first step is gathering your commands into a single variable. Bash heredocs handle this cleanly, and a quoted delimiter stops the shell from expanding variables inside the block.
read -r -d '' CMDS <<'CMDS' sudo apt install -y build-essential sudo cpanm JSON::XS CMDS
The -r flag stops the shell from interpreting backslashes, and -d '' tells read to keep reading until the end of the file. After this step, the $CMDS variable holds your full command list and is ready to pipe into Perl.

Part 2: THE PERL ONE-LINER ANATOMY

The actual execution happens in this Perl command.
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, so 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.

perl.gg

✓ Document: Doneone-liners / 7.9 KiB▧