one-liners intermediate

How to replace text in-place across files with perl -pi?

Question

How to replace text in-place across files with perl -pi?

Performing in-place text replacement across files with Perl’s -pi command-line flags is powerful, but using it inside a sandbox or script requires understanding how -p, -i, and -e work together.

Why the original snippet failed in the sandbox

The error syntax error at - line 1, near "pi -e " occurs because the flags -p and -i must be passed to the perl interpreter itself when called from the shell. When running Perl code directly (e.g. via perl - expecting a program on STDIN), you cannot embed -pi inside your code. Those are command-line options, not Perl code.

In other words, perl -pi -e 's/foo/bar/g' *.txt is a shell command; inside Perl itself, you must manually simulate what those flags do to edit files.

How to simulate perl -pi in a Perl script

The key is:

  • Read each file line-by-line
  • Do the substitution on each line
  • Write back to the same file, optionally saving a backup first

This can be done in a simple script that you run as perl - (feeding the script through STDIN). Here’s a complete example that replaces foo with bar in two sample files, mimicking perl -pi.bak -e 's/foo/bar/g':

use strict;
use warnings;

# Sample files to edit
my @files = ('example1.txt', 'example2.txt');

# Create sample files with content including 'foo'
for my $file (@files) {
    open my $fh, '>', $file or die "Cannot write $file: $!";
    print $fh "foo is here\nanother foo line\n";
    close $fh;
}

for my $file (@files) {
    # Backup original file
    rename $file, "$file.bak" or die "Cannot backup $file: $!";

    open my $in,  '<', "$file.bak" or die $!;
    open my $out, '>', $file       or die $!;

    while (<$in>) {
        s/foo/bar/g;  # Substitute foo with bar
        print $out $_;
    }

    close $in;
    close $out;
}

# Print modified file contents
for my $file (@files) {
    print "Contents of $file after substitution:\n";
    open my $fh, '<', $file or die $!;
    print while <$fh>;
    close $fh;
}

Key Perl Concepts Illustrated

  • @files: Array holding filenames — sigils like @ indicate arrays.
  • open: Opens a filehandle for reading (<) or writing (>).
  • while (<$in>): Reads line-by-line from input filehandle.
  • s/foo/bar/g;: Regular expression substitution (all occurrences in the line).
  • rename: Used to make a backup before editing (like -i.bak).

This manual approach is what perl -pi shorthand handles internally.

Common pitfalls when using -pi in command line

  • Make sure you run perl -pi -e 's/foo/bar/g' files from a shell, not in a Perl script.
  • Escaping issues: In shells like Bash, use single quotes to protect Perl code, but on Windows CMD you may need double quotes.
  • Backup extension: -i.bak creates backups; -i alone edits without backups—be careful!
  • Binary files: line-by-line edits may corrupt binary data.

Summary

To replace text in-place across files from a shell, use:

perl -pi.bak -e 's/foo/bar/g' *.txt

To emulate that behavior inside a Perl script (runnable with perl -), read and rewrite files line-by-line making backups yourself, as shown above.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 12ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
Contents of example1.txt after substitution:
bar is here
another bar line
Contents of example2.txt after substitution:
bar is here
another bar line
STDERR
(empty)

Was this helpful?

Related Questions