I/O Operations in Perl
Learn console output, reading from standard input, and file reading, writing, and error handling in Perl with Docker-ready examples
Perl was born from the need to shuffle text between programs, files, and terminals, so input and output are woven deep into the language. You have already used print to say “Hello, World!” — this tutorial goes further, covering formatted output, reading from standard input, and the file handling that makes Perl a favorite for log parsing and system administration.
As a dynamic, weakly-typed language, Perl keeps I/O refreshingly direct: there are no stream classes to instantiate and no imports required for the basics. You open a filehandle, read or write scalars and lists through it, and close it. Perl’s context sensitivity shows up here too — reading a filehandle in scalar context gives you one line, while list context slurps every line into an array.
Along the way you will meet three idioms that define Perl I/O: the $! variable that carries the last system error message, the open ... or die pattern for failing loudly, and the three-argument form of open that keeps filenames and modes safely separated.
Console Output: print, say, and printf
You have three main tools for writing to the terminal. print writes exactly what you give it with no automatic newline, say (from use v5.10 or use feature 'say') appends a newline for you, and printf formats values against a template just like C.
Create a file named output.pl:
| |
The printf format specifiers control width and type: %-10s left-justifies a string in a 10-character field, %3d right-justifies an integer in a 3-character field, and %.2f shows a float with two decimal places. This is the same formatting mini-language used by C and many other languages.
Reading from Standard Input
The <STDIN> operator (also written as <>) reads from standard input. In scalar context it returns one line at a time — including the trailing newline — so chomp is almost always the next step. The while (my $line = <STDIN>) loop is the canonical way to process input line by line until end-of-input.
Create a file named input.pl:
| |
When you run a script interactively, you can prompt first with print "Enter your name: "; and then read a single line with my $name = <STDIN>;. In the Docker example below we instead pipe input into the script, which is how Perl programs usually receive data in real automation pipelines.
Reading and Writing Files
The open function connects a filehandle to a file. Always prefer the three-argument form — open($fh, MODE, $filename) — because it keeps the mode (< read, > write/truncate, >> append) separate from the filename, avoiding a whole class of bugs. Pair every open with or die "...: $!" so failures report the underlying system error stored in $!.
The example below writes three lines, then reads them back two different ways: line by line with a while loop, and all at once by evaluating the filehandle in list context.
Create a file named file_io.pl:
| |
Notice that print, printf, and say all accept a filehandle as their first argument (with no comma after it) to redirect output away from the terminal and into a file. Using > truncates any existing file; switching to >> would append instead.
Handling I/O Errors Gracefully
die is perfect when a missing file should halt the program, but sometimes you want to recover and keep going. Because open returns false on failure, you can test it in an if and take a different path. For code that might die deeper down, wrap it in eval { ... } and inspect the result — this is Perl’s classic exception-catching idiom.
Create a file named errors.pl:
| |
warn writes to standard error (STDERR) instead of standard output, which is the correct channel for diagnostics — it keeps error text out of a program’s real data output when the two streams are redirected separately.
Running with Docker
| |
The -i flag on the input example keeps STDIN open so the piped data reaches the container. The -v $(pwd):/app mount lets file_io.pl create notes.txt in your current directory so you can inspect it afterward.
Expected Output
Running output.pl:
No newline here - still the same line
This line ends automatically
Name: Alice Age: 30
Pi is roughly 3.14
Hex: ff Octal: 10
apple, banana, cherry
Running input.pl with apple, banana, cherry piped in:
Line 1: apple
Line 2: banana
Line 3: cherry
Total lines read: 3
Running file_io.pl:
Wrote 3 lines to notes.txt
Line 1: Perl was created in 1987
Line 2: It excels at text processing
Line 3: say works with filehandles too
Total lines: 3
Running errors.pl (the first line is written to STDERR):
Could not open does_not_exist.txt: No such file or directory
Handled the error and kept running
Caught the exception, program continues
Program finished normally
Key Concepts
- Three ways to output —
print(no newline),say(adds a newline), andprintf(formatted); all three accept a filehandle as their first argument to write to files instead of the terminal. <$fh>is context-sensitive — reading a filehandle in scalar context returns one line, while list context (my @lines = <$fh>) slurps every remaining line into an array.- Always
chomp— lines read from<STDIN>or a file keep their trailing newline;chompremoves it so comparisons and concatenation behave as expected. - Use three-argument
open—open($fh, '<', $file)separates the mode from the filename, which is safer than the older two-argument form. $!carries the error — after a failed system call,$!holds the human-readable reason (e.g. “No such file or directory”); include it in everydieorwarnmessage.open ... or diefails loudly — never ignore anopenreturn value; eitherdieto stop or test the return value withifto recover gracefully.- STDERR for diagnostics —
warnandprint STDERR ...send messages to standard error, keeping them separate from a program’s real data on standard output. eval { }catches exceptions — wrap risky I/O inevaland check whether it succeeded to trap adieand continue running.
Comments
Loading comments...
Leave a Comment