# Filehandle and printing state Seven variables that drive Perl’s I/O. They are *globals* — setting `$/` in one routine changes how every other routine in the same process reads from a filehandle. The discipline that keeps that from being a disaster is `local`-isation: every change to a variable on this page should be inside a `local` block unless the program genuinely wants the new value to be permanent. | Variable | Reads as | Default | Used by | |------------|-------------------------|------------------|----------------------------------------| | `$/` | input record separator | `"\n"` | `<$fh>`, `readline` | | `$\` | output record separator | `undef` | `print`, `printf`, `say` (forced `\n`) | | `$,` | output field separator | `undef` | `print`, `printf` (between args) | | `$"` | list separator | `" "` | array interpolation `"@arr"` | | \`$ | \` | output autoflush | `0` | | `$.` | current line number | `0` | last filehandle read | | `$;` | subscript separator | `"\034"` | `$h{$x, $y}` multidim emulation | ## `$/` — the input record separator Controls what [`<$fh>`](../perlfunc/readline.md) and [`readline`](../perlfunc/readline.md) treat as the end of one record. The default `"\n"` means *line-by-line* reading; setting it to other values produces other reading modes. ### Line mode (the default) ```perl while (my $line = <$fh>) { chomp $line; # strips the terminator $/ process($line); } ``` [`chomp`](../perlfunc/chomp.md) removes whatever `$/` currently holds — when you change `$/`, `chomp` follows it. ### Slurp mode `undef $/` makes `<>` read the entire file in one go: ```perl my $whole_file = do { local $/; <$fh>; }; ``` The `local` is essential. Without it, every other piece of code that subsequently reads from a filehandle in the same process will silently slurp. ### Paragraph mode `local $/ = "";` reads paragraph-at-a-time, splitting on runs of two or more newlines: ```perl { local $/ = ""; while (my $para = <$fh>) { # $para ends with exactly two newlines (or one at EOF) process_paragraph($para); } } ``` This is awk’s `RS=""` behaviour. Leading blank lines at the start of the file are silently skipped. ### Fixed-record mode `local $/ = \N` reads `N` bytes per call: ```perl local $/ = \4096; # binary 4-KiB chunks while (defined(my $chunk = <$fh>)) { process($chunk); } ``` The reference is to a number, not the number itself. This is the right shape for reading binary data, network packets, or doing bulk copy without scanning for `\n`. ### Multi-character terminators ```perl local $/ = "\r\n"; # CRLF mode local $/ = "\nEND-OF-RECORD\n"; # custom marker ``` The terminator is a literal string, not a regex. ## `$\` — the output record separator Appended to every [`print`](../perlfunc/print.md) call. Default is `undef` (nothing appended). Setting it changes every subsequent `print`: ```perl { local $\ = "\n"; # all prints get a trailing newline print "first"; print "second"; } # Output: "first\nsecond\n" ``` This is the natural fit for [`-l`](../../../guide/oneliner/switches.md) on the command line — `-l` sets `$\` to `\n`. In script code, `local $\ = "\n"` inside a tight reporting loop is occasionally worth it; otherwise `say` (which forces `\n` regardless of `$\`) is the cleaner spelling. ## `$,` — the output field separator Inserted between `print`’s arguments. Default is `undef`: ```perl print "a", "b", "c"; # "abc" { local $, = ", "; print "a", "b", "c"; # "a, b, c" } { local $, = "\t"; print @items; # tab-separated record } ``` `$,` is per-print, not per-line — it does not separate *successive* `print` calls. Combine with `$\` for full TSV-style output: ```perl local ($,, $\) = ("\t", "\n"); print 'col1', 'col2', 'col3'; # "col1\tcol2\tcol3\n" ``` ## `$"` — the list separator Joins array elements when an array is interpolated into a double-quoted string. Default is `" "` (single space): ```perl my @arr = (1, 2, 3); print "items: @arr\n"; # "items: 1 2 3" { local $" = ', '; print "items: @arr\n"; # "items: 1, 2, 3" } { local $" = "\n "; print "items:\n @arr\n"; # "items:\n 1\n 2\n 3" } ``` `$"` is *only* consulted on interpolation. `print @arr` (no quotes) uses `$,`, not `$"`. ## `$|` — output autoflush Forces a flush after every write on the **currently selected** filehandle: ```perl $| = 1; # autoflush STDOUT print "Loading..."; sleep 1; # appears immediately, not at exit ``` The ”currently selected“ qualification matters. By default, `select` returns `STDOUT`, so `$| = 1` autoflushes STDOUT. To autoflush a different handle: ```perl my $old = select($log_fh); $| = 1; select($old); # restore selection ``` The slightly nicer modern spelling uses [`IO::Handle`](../../IO.md): ```perl $log_fh->autoflush(1); ``` `$|` is read-as-boolean: `print $|` shows `1` or `0`. ## `$.` — current line number The line number of the last `<>`-style read. Each filehandle has its own counter; reading from a different handle aliases `$.` to that handle’s count: ```perl while (<$fh>) { print "$.: $_"; # numbered listing } # After the loop, $. is the total number of lines read. ``` `$.` is reset when the filehandle is *closed*. Reopening (without an explicit close in between) does **not** reset. For multi-file iteration via `<>`, lines are numbered cumulatively across files unless you explicitly close `ARGV` at each file boundary — see [`eof`](../perlfunc/eof.md) for the standard `close ARGV if eof;` idiom. ## `$;` — the subscript separator Used to fake multi-dimensional hashes — a deeply legacy feature preserved for backward compatibility: ```perl $h{$x, $y} = $value; # equivalent to $h{"$x\034$y"} ``` The default value is `"\034"` (FS, ”file separator“, an obscure ASCII control byte). Real multi-dimensional structures should use nested hash refs (`$h{$x}{$y}`); `$;` exists because Perl 4 had no proper references. ## When you actually localise these The most common shape, by far: ```perl sub slurp_text { my ($path) = @_; open my $fh, '<', $path or die "open $path: $!"; local $/; # slurp inside this sub only return <$fh>; } sub paragraphs_of { my ($path) = @_; open my $fh, '<', $path or die "open $path: $!"; local $/ = ""; return <$fh>; # list context: list of paragraphs } sub csv_print { my (@row) = @_; local ($,, $\) = (",", "\n"); print @row; } ``` The cost of forgetting `local` is invisible at write time and catastrophic at use time — a subroutine that ”just sets `$/`“ can break unrelated code reading from completely different filehandles. Treat `$/`, `$\`, `$,`, `$"` as *global mode flags*: always set them with `local`. ## See also - [`open`](../perlfunc/open.md), [`readline`](../perlfunc/readline.md), [`<$fh>`](../perlfunc/readline.md) — the consumers of `$/`. - [`print`](../perlfunc/print.md), [`printf`](../perlfunc/printf.md), [`say`](../perlfunc/say.md) — the consumers of `$\`, `$,`. - [`chomp`](../perlfunc/chomp.md) — removes whatever `$/` currently holds; pairs with `$/` changes. - [`eof`](../perlfunc/eof.md) — the `close ARGV if eof` idiom that makes `$.` count per-file across `<>`. - [`select`](../perlfunc/select.md) — selects the filehandle that `$|` and the unprefixed `$,`/`$\` apply to. - [`IO::Handle`](../../IO.md) — provides `autoflush`, `output_record_separator`, etc. as method calls. - [`local`](../perlfunc/local.md) — the safe way to change any variable on this page. - [Interpolation](../perldata/interpolation.md) — how `$"` shapes array expansion inside double-quoted strings.