Can a Perl program know the line number where __DATA__ begins? - perl

Is there a way to get the line number (and maybe filename) where a __DATA__ token was coded? Or some other way to know the actual line number in the original source file where a line of data read from the DATA filehandle came from?
Note that $. counts from 1 when reading from the DATA filehandle. So if the line number of the __DATA__ token were added to $. it would be what I'm looking for.
For example:
#!/usr/bin/perl
while (<DATA>) {
my $n = $. + WHAT??;
die "Invalid data at line $n\n" if /bad/;
}
__DATA__
something good
something bad
I want this to say "Invalid data at line 9", not "line 2" (which is what you get if $. is used by itself).

In systems that support /proc/<pid> virtual filesystems (e.g., Linux), you can do:
# find the file where <DATA> handle is read from
my $DATA_FILE = readlink("/proc/$$/fd/" . fileno(*DATA));
# find the line where DATA begins
open my $THIS, "<", $DATA_FILE;
my #THIS = <$THIS>;
my ($DATA_LINE) = grep { $THIS[$_] =~ /^__DATA__\b/ } 0 .. $#THIS;

File don't actually have lines; they're just sequences of bytes. The OS doesn't even offer the capability of getting a line from a file, so it has no concept of line numbers.
Perl, on the other hand, does keep track of a line number for each handle. It is accessed via $..
However, the Perl handle DATA is created from a file descriptor that's already been moved to the start of the data —it's the file descriptor that Perl itself uses to load and parse the file— so there's no record of how many lines have already been read. So the line 1 of DATA is the first line after __DATA__.
To correct the line count, one must seek back to the start of the file, and read it line by line until the file handle is back at the same position it started.
#!/usr/bin/perl
use strict;
use warnings qw( all );
use Fcntl qw( SEEK_SET );
# Determines the line number at the current file position without using «$.».
# Corrects the value of «$.» and returns the line number.
# Sets «$.» to «1» and returns «undef» if unable to determine the line number.
# The handle is left pointing to the same position as when this was called, or this dies.
sub fix_line_number {
my ($fh) = #_;
( my $initial_pos = tell($fh) ) >= 0
or return undef;
seek($fh, 0, SEEK_SET)
or return undef;
$. = 1;
while (<$fh>) {
( my $pos = tell($fh) ) >= 0
or last;
if ($pos >= $initial_pos) {
if ($pos > $initial_pos) {
seek($fh, $initial_pos, SEEK_SET)
or die("Can't reset handle: $!\n");
}
return $.;
}
}
seek($fh, $initial_pos, SEEK_SET)
or die("Can't reset handle: $!\n");
$. = 1;
return undef;
}
my $prefix = fix_line_number(\*DATA) ? "" : "+";
while (<DATA>) {
printf "%s:%s: %s", __FILE__, "$prefix$.", $_;
}
__DATA__
foo
bar
baz
Output:
$ ./a.pl
./a.pl:48: foo
./a.pl:49: bar
./a.pl:50: baz
$ perl <( cat a.pl )
/dev/fd/63:+1: foo
/dev/fd/63:+2: bar
/dev/fd/63:+3: baz

Perl keeps track of the file and line at which each symbol is created. A symbol is normally created when the parser/compiler first encounters it. But if __DATA__ is encountered before DATA is otherwise created, this will create the symbol. We can take advantage of this to set the line number associated with the file handle in DATA.
For the case where the Package::DATA handle is not used in Package.pm itself, the line number of the __DATA__ token could be obtained via B::GV->LINE on the DATA handle:
$ cat Foo.pm
package Foo;
1;
__DATA__
good
bad
$ perl -I. -MFoo -MB -e '
my $ln = B::svref_2object(\*Foo::DATA)->LINE;
warn "__DATA__ at line $ln\n";
Foo::DATA->input_line_number($ln);
while(<Foo::DATA>){ die "no good" unless /good/ }
'
__DATA__ at line 4
no good at -e line 1, <DATA> line 6.
In the case where the DATA handle is referenced in the file itself, a possible kludge would be to use an #INC hook:
$ cat DH.pm
package DH;
unshift #INC, sub {
my ($sub, $fname) = #_;
for(#INC){
if(open my $fh, '<', my $fpath = "$_/$fname"){
$INC{$fname} = $fpath;
return \'', $fh, sub {
our (%ln, %pos);
if($_){ $pos{$fname} += length; ++$ln{$fname} }
}
}
}
};
$ cat Bar.pm
package Bar;
print while <DATA>;
1;
__DATA__
good
bad
$ perl -I. -MDH -MBar -e '
my $fn = "Bar.pm";
warn "__DATA__ at line $DH::ln{$fn} pos $DH::pos{$fn}\n";
seek Bar::DATA, $DH::pos{$fn}, 0;
Bar::DATA->input_line_number($DH::ln{$fn});
while (<Bar::DATA>){ die "no good" unless /good/ }
'
good
bad
__DATA__ at line 6 pos 47
no good at -e line 6, <DATA> line 8.
Just for the sake of completion, in the case where you do have control over the file, all could be easily done with:
print "$.: $_" while <DATA>;
BEGIN { our $ln = __LINE__ + 1; DATA->input_line_number($ln) }
__DATA__
...
You can also use the first B::GV solution, provided that you reference the DATA handle via an eval:
use B;
my ($ln, $data) = eval q{B::svref_2object(\*DATA)->LINE, \*DATA}; die $# if $#;
$data->input_line_number($ln);
print "$.: $_" while <$data>;
__DATA__
...
None of these solutions assumes that the source file are seekable (except if you want to read the DATA more than once, as I did in the second example), or try to reparse your files, etc.

Comparing the end of the file to itself in reverse might do what you want:
#!/usr/bin/perl
open my $f, "<", $0;
my #lines;
my #dataLines;
push #lines ,$_ while <$f>;
close $f;
push #dataLines, $_ while <DATA>;
my #revLines= reverse #lines;
my #revDataLines=reverse #dataLines;
my $count=#lines;
my $offset=0;
$offset++ while ($revLines[$offset] eq $revDataLines[$offset]);
$count-=$offset;
print "__DATA__ section is at line $count\n";
__DATA__
Hello there
"Some other __DATA__
lkjasdlkjasdfklj
ljkasdf
Running give a output of :
__DATA__ section is at line 19
The above script reads itself (using $0 for file name) into the #lines array and reads the DATA file into the #dataLines array.
The arrays are reversed and then compared element by element until they are different. The number of lines are tracked in $offset and this is subtracted from the $count variable which is the number of lines in the file.
The result is the line number the DATA section starts at. Hope that helps.

Thank you #mosvy for the clever and general idea.
Below is a consolidated solution which works anywhere. It uses a symbolic reference instead of eval to avoid mentioning "DATA" at compile time, but otherwise uses the same ideas as mosvy.
The important point is that code in a package containing __DATA__ must not refer to the DATA symbol by name so that that symbol won't be created until the compiler sees the __DATA__ token. The way to avoid mentioning DATA is to use a filehandle ref created at run-time.
# Get the DATA filehandle for a package (default: the caller's),
# fixed so that "$." provides the actual line number in the
# original source file where the last-read line of data came
# from, rather than counting from 1.
#
# In scalar context, returns the fixed filehandle.
# In list context, returns ($fh, $filename)
#
# For this to work, a package containing __DATA__ must not
# explicitly refer to the DATA symbol by name, so that the
# DATA symbol (glob) will not yet be created when the compiler
# encounters the __DATA__ token.
#
# Therefore, use the filehandle ref returned by this
# function instead of DATA!
#
sub get_DATA_fh(;$) {
my $pkg = $_[0] // caller;
# Using a symbolic reference to avoid mentioning "DATA" at
# compile time, in case we are reading our own module's __DATA__
my $fh = do{ no strict 'refs'; *{"${pkg}::DATA"} };
use B;
$fh->input_line_number( B::svref_2object(\$fh)->LINE );
wantarray ? ($fh, B::svref_2object(\$fh)->FILE) : $fh
}
Usage examples:
my $fh = get_DATA_fh; # read my own __DATA__
while (<$fh>) { print "$. : $_"; }
or
my ($fh,$fname) = get_DATA_fh("Otherpackage");
while (<$fh>) {
print " $fname line $. : $_";
}

Related

Split file Perl

I want to split parts of a file. Here is what the start of the file looks like (it continues in same way):
Location Strand Length PID Gene
1..822 + 273 292571599 CDS001
906..1298 + 130 292571600 trxA
I want to split in Location column and subtract 822-1 and do the same for every row and add them all together. So that for these two results the value would be: (822-1)+1298-906) = 1213
How?
My code right now, (I don't get any output at all in the terminal, it just continue to process forever):
use warnings;
use strict;
my $infile = $ARGV[0]; # Reading infile argument
open my $IN, '<', $infile or die "Could not open $infile: $!, $?";
my $line2 = <$IN>;
my $coding = 0; # Initialize coding variable
while(my $line = $line2){ # reading the file line by line
# TODO Use split and do the calculations
my #row = split(/\.\./, $line);
my #row2 = split(/\D/, $row[1]);
$coding += $row2[0]- $row[0];
}
print "total amount of protein coding DNA: $coding\n";
So what I get from my code if I put:
print "$coding \n";
at the end of the while loop just to test is:
821
1642
And so the first number is correct (822-1) but the next number doesn't make any sense to me, it should be (1298-906). What I want in the end outside the loop:
print "total amount of protein coding DNA: $coding\n";
is the sum of all the subtractions of every line i.e. 1213. But I don't get anything, just a terminal that works on forever.
As a one-liner:
perl -nE '$c += $2 - $1 if /^(\d+)\.\.(\d+)/; END { say $c }' input.txt
(Extracting the important part of that and putting it into your actual script should be easy to figure out).
Explicitly opening the file makes your code more complicated than it needs to be. Perl will automatically open any files passed on the command line and allow you to read from them using the empty file input operator, <>. So your code becomes as simple as this:
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
my $total;
while (<>) {
my ($min, $max) = /(\d+)\.\.(\d+)/;
next unless $min and $max;
$total += $max - $min;
}
say $total;
If this code is in a file called adder and your input data is in add.dat, then you run it like this:
$ adder add.dat
1213
Update: And, to explain where you were going wrong...
You only ever read a single line from your file:
my $line2 = <$IN>;
And then you continually assign that same value to another variable:
while(my $line = $line2){ # reading the file line by line
The comment in this line is wrong. I'm not sure where you got that line from.
To fix your code, just remove the my $line2 = <$IN> line and replace your loop with:
while (my $line = <$IN>) {
# your code here
}

Perl : Adding 2 files line by line

I am a beginner in perl, so please bear with me.
I have 2 files:
1
2
3
and
2
4
5
6
I want to create a new file that is the sum of the above 2 files:
output file:
3
6
8
6
What I am doing right now is reading the files as arrays and adding them element by element.
To add the arrays I am using the following:
$asum[#asum] = $array1[#asum] + $array2[#asum] while defined $array1[#asum] or defined $array2[#asum];
But this is giving the following error:
Argument "M-oM-;M-?3" isn't numeric in addition (+) at perl_ii.pl line 30.
Argument "M-oM-;M-?1" isn't numeric in addition (+) at perl_ii.pl line 30.
Use of uninitialized value in addition (+) at perl_ii.pl line 30.
I am using the following code to read files as arrays:
use strict;
use warnings;
my #array1;
open(my $fh, "<", "file1.txt") or die "Failed to open file1\n";
while(<$fh>) {
chomp;
push #array1, $_;
}
close $fh;
my #array2;
open(my $fh1, "<", "file2.txt") or die "Failed to open file2\n";
while(<$fh1>) {
chomp;
push #array2, $_;
}
close $fh1 ;
Anyone could tell me how to fix this, or give a better approach altogether?
Here is another Perl solution that makes use of the diamond, <>, file read operator. This reads in files specified on the command line, (rather than explicitly opening them within the program). Sorry, I can't find the part of the docs that explains this for a read.
The command line for this program would look like:
perl myprogram.pl file1 file2 > outputfile
Where file1 and file2 are the 2 input files and outputfile is the file you want to print the results of the addition.
#!/usr/bin/perl
use strict;
use warnings;
my #sums;
my $i = 0;
while (my $num = <>) {
$sums[$i++] += $num;
$i = 0 if eof;
}
print "$_\n" for #sums;
Note: $i is reset to zero at the end of file, (in this case after the first file is read). Actually, it is also reset to 0 after the second file is read. This has no effect on the program however, because there are no files to be read after the second file in your example.
The following solution makes the memory footprint of the program independent of the sizes of the files. Instead, now the memory footprint only depends on the number of files:
#!/usr/bin/env perl
use strict;
use warnings;
use Carp qw( croak );
use List::Util qw( sum );
use Path::Tiny;
run(#ARGV);
sub run {
my #readers = map make_reader($_), #_;
while (my #obs = grep defined, map $_->(), #readers) {
print sum(#obs), "\n";
}
return;
}
sub make_reader {
my $fname = shift;
my $fhandle = path( $fname )->openr;
my $is_readable = 1;
sub {
return unless $is_readable;
my $line = <$fhandle>;
return $line if defined $line;
close $fhandle
or croak "Cannot close '$fname': $!";
$is_readable = 0;
return;
}
}
You have two different problems with your script now:
First error
Argument "M-oM-;M-?3" isn't numeric in addition (+) at perl_ii.pl line
30
happens because your input files are saved in Unicode and first line is read with "\xFF\xFE" BOM bytes.
To fix it simply, just resave the files as ANSI text. If Unicode is required, then remove these bytes from first string you read from file.
Second error
Use of uninitialized value in addition (+) at perl_ii.pl line 30.
happens because you access 4th element in first array that doesn't exist. Remember, you select maximal input array length as index limit. To fix it just add following condition for input element:
$asum[#asum] = (#asum < #array1 ? $array1[#asum] : 0) + (#asum < #array2 ? $array2[#asum] : 0) while defined $array1[#asum] or defined $array2[#asum];
The logic of reading your two files is the same, and I suggest using a subroutine for that and calling it twice:
#!/usr/bin/env perl
use strict;
use warnings;
my #array1 = read_into_array('file1.txt');
my #array2 = read_into_array('file2.txt');
sub read_into_array
{
my $filename = shift;
my #array;
open(my $fh, "<", $filename) or die "Failed to open $filename: $!\n";
while(<$fh>) {
chomp;
push #array, $_;
}
close $fh;
return #array;
}
But that's just an observation I made and not a solution to your problem. As CodeFuller already said, you should re-save your files as plain ASCII instead of UTF-8.
The second problem, Use of uninitialized value in addition (+), can also be solved with the Logical Defined Or operator // which was introduced in Perl 5.10:
my #asum;
$asum[#asum] = ($array1[#asum] // 0)
+ ($array2[#asum] // 0)
while defined $array1[#asum] or defined $array2[#asum];
No, this is not a comment, but an operator very similar to ||. The difference is that it triggers when the left-hand-side (lhs) is undef while the || triggers when the lhs is falsy (i.e. 0, '' or undef). Thus
$array1[#asum] // 0
gives 0 if $array1[#asum] is undef. It's the same as
defined($array1[#asum]) ? $array1[#asum] : 0
A different approach altogether:
$ paste -d '+' file1 file2 | sed 's/^+//;s/+$//' | bc
3
6
8
6
The paste command prints the files next to each other, separated by a + sign:
$ paste -d '+' file1 file2
1+2
2+4
3+5
+6
The sed command removes leading and trailing + signs, because those trip up bc:
$ paste -d '+' file1 file2 | sed 's/^+//;s/+$//'
1+2
2+4
3+5
6
And bc finally calculates the sums.
Here’s a rendition of Sinan’s approach in a more Perlish form:
#!/usr/bin/env perl
use 5.010; use strict; use warnings;
use autodie;
use List::Util 'sum';
my #fh = map { open my $fh, '<', $_; $fh } #ARGV;
while ( my #value = grep { defined } map { scalar readline $_ } #fh ) {
say sum #value;
#fh = grep { not eof $_ } #fh if #value < #fh;
}

Unexpected behaviour of filehandle in conjunction with subroutine call - why?

I am reading a file line by line and want to process each line through a subroutine. Since I am not interested in the line itself, I put the read from the filehandle directly into the subroutine call. However, this leads to unexpected behaviour I don't quite understand.
I created a minimal example demonstrating the effect:
#!/usr/bin/perl
use strict;
use warnings;
use Carp;
use English qw( -no_match_vars );
print "This works as expected:\n";
open my $TEST1, '<', 'filetest1.txt' or croak "Can't open filetest1.txt - $ERRNO";
my $line1 = <$TEST1>;
print_line( $line1 );
while ( 1 ) {
last if eof $TEST1;
$line1 = <$TEST1>;
print $line1;
}
close $TEST1;
print "\n";
print "Unexpected effect here:\n";
open my $TEST2, '<', 'filetest1.txt' or croak "Can't open filetest1.txt - $ERRNO";
print_line(<$TEST2>); # this works, but just once
while ( 1 ) {
last if eof $TEST2; # is triggered immediately
print "This is never printed\n";
print_line(<$TEST2>);
}
close $TEST2;
sub print_line {
my $line = shift;
print $line;
return 1;
}
Content of filetest1.txt:
test line 1
test line 2
test line 3
test line 4
test line 5
Result of the script:
This works as expected:
test line 1
test line 2
test line 3
test line 4
test line 5
Unexpected effect here:
test line 1
It seems that when I read the next line directly in the subroutine call, it works exactly once and then eof is triggered. I haven't found any explanation for that effect, and it forces me to create the variable $line1 just to pass the line to the subroutine.
I'm looking for an explanation why that happens, and consequently I'd like to understand the limits of what I can or cannot do with a filehandle.
In your code print_line(<$FH>); the reading from the filehandle will be will be done in wantarray-mode meaning you don't read a single line but the whole file. And in your subroutine you just use the first line and discard the rest. Thats why the filehandle is empty after your first loop encounter.
You could just provide the filehandle to the subroutine and read a line there:
open my $FH , '<' , 'somefile' or die "Cannot read: $!" ;
while( ! eof $FH ) {
print_line( $FH ) ;
}
sub print_line {
my ( $fh ) = #_ ;
my $line = <$fh> ;
print $line ;
}
You have a context problem. The $TEST1 read is in scalar context, so it only read one line. The $TEST2 read is in list context, so all the lines from the file are read and print_line() is called with a list of them as its arguments. So the second time you try to read from $TEST2 you get EOF, since all the lines were read the first time.

Storing large file in array is not possible?

There is a process which stores the file in an array. Unfortunately when the file is too big (Let's say 800K lines or more than 60 MB) an error is returned like "Out of memory!". Is there any solution to this? For example the following code throw "Out of memory!".
#! /usr/bin/perl
die unless (open (INPUT, "input.txt"));
#file=<INPUT>; # It fails here
print "File stored in array\n"; # It never reaches here
$idx=0;
while ($idx < #file) {
$idx++;
}
print "The line count is = $idx\n";
I'd use Tie::File for that:
use Tie::File;
my #file
tie #file, 'Tie::File', "input.txt";
print "File reflected in array\n";
print "The line count is ", scalar(#file);
Most of the time, you don't need to read in the whole file at once. The readline operator returns only one line at a time when called in scalar context:
1 while <INPUT>; # read a line, and discard it.
say "The line count is = $.";
The $. special variable is the line number of the last read filehandle.
Edit: Line counting was just an example
Perl has no problem with large arrays, it just seems that your system doesn't have enough memory. Be aware that Perl arrays use more memory than C arrays, as a scalar allocate additional memory for flags etc, and because arrays grow in increasing steps.
If memory is an issue, you have to transform your algorithm from one that has to load a whole file into memory to one that only keeps one line at a time.
Example: Sorting a multi-gigabyte file. The normal approach print sort <$file> won't work here. Instead, we sort portions of the file, write them to tempfiles, and then switch between the tempfiles in a clever way to produce one sorted output:
use strict; use warnings; use autodie;
my $blocksize = shift #ARGV; # take lines per tempfile as command line arg
mkdir "/tmp/$$"; # $$ is the process ID variable
my $tempcounter = 0;
my #buffer;
my $save_buffer = sub {
$tempcounter++;
open my $tempfile, ">", "/tmp/$$/$tempcounter";
print $tempfile sort #buffer;
#buffer = ();
};
while (<>) {
push #buffer, $_;
$save_buffer->() if $. % $blocksize == 0;
}
$save_buffer->();
# open all files, read 1st line
my #head =
grep { defined $_->[0] }
map { open my $fh, "<", $_; [scalar(<$fh>), $fh] }
glob "/tmp/$$/*";
# sort the line-file pairs, pick least
while((my $least, #head) = sort { $a->[0] cmp $b->[0] } #head){
my ($line, $fh) = #$least; print $line;
# read next line
if (defined($line = <$fh>)){
push #head, [$line, $fh];
}
}
# clean up afterwards
END {
unlink $_ for glob "/tmp/$$/*";
rmdir "/tmp/$$";
}
Could be called like $ ./sort-large-file 10000 multi-gig-file.txt >sorted.txt.
This general approach can be applied to all kinds of problems. This is a “divide and conquer” strategy: If the problem is too big, solve a smaller problem, and then combine the pieces.

How to remove one line from a file using Perl?

I'm trying to remove one line from a text file. Instead, what I have wipes out the entire file. Can someone point out the error?
removeReservation("john");
sub removeTime() {
my $name = shift;
open( FILE, "<times.txt" );
#LINES = <FILE>;
close(FILE);
open( FILE, ">times.txt" );
foreach $LINE (#LINES) {
print NEWLIST $LINE unless ( $LINE =~ m/$name/ );
}
close(FILE);
print("Reservation successfully removed.<br/>");
}
Sample times.txt file:
04/15/2012&08:00:00&bob
04/15/2012&08:00:00&john
perl -ni -e 'print unless /whatever/' filename
Oalder's answer is correct, but he should have tested whether the open statements succeeded or not. If the file times.txt doesn't exist, your program would continue on its merry way without a word of warning that something terrible has happened.
Same program as oalders' but:
Testing the results of the open.
Using the three part open statement which is more goof proof. If your file name begins with > or |, your program will fail with the old two part syntax.
Not using global file handles -- especially in subroutines. File handles are normally global in scope. Imagine if I had a file handle named FILE in my main program, and I was reading it, I called this subroutine. That would cause problems. Use locally scoped file handle names.
Variable names should be in lowercase. Constants are all uppercase. It's just a standard that developed over time. Not following it can cause confusion.
Since oalders put the program in a subroutine, you should pass the name of your file in the subroutine as well...
Here's the program:
#!/usr/bin/env perl
use strict;
use warnings;
removeTime( "john", "times.txt" );
sub removeTime {
my $name = shift;
my $time_file = shift;
if (not defined $time_file) {
#Make sure that the $time_file was passed in too.
die qq(Name of Time file not passed to subroutine "removeTime"\n);
}
# Read file into an array for processing
open( my $read_fh, "<", $time_file )
or die qq(Can't open file "$time_file" for reading: $!\n);
my #file_lines = <$read_fh>;
close( $read_fh );
# Rewrite file with the line removed
open( my $write_fh, ">", $time_file )
or die qq(Can't open file "$time_file" for writing: $!\n);
foreach my $line ( #file_lines ) {
print {$write_fh} $line unless ( $line =~ /$name/ );
}
close( $write_fh );
print( "Reservation successfully removed.<br/>" );
}
It looks like you're printing to a filehandle which you have not yet defined. At least you haven't defined it in your sample code. If you enable strict and warnings, you'll get the following message:
Name "main::NEWLIST" used only once: possible typo at remove.pl line 16.
print NEWLIST $LINE unless ($LINE =~ m/$name/);
This code should work for you:
#!/usr/bin/env perl
use strict;
use warnings;
removeTime( "john" );
sub removeTime {
my $name = shift;
open( FILE, "<times.txt" );
my #LINES = <FILE>;
close( FILE );
open( FILE, ">times.txt" );
foreach my $LINE ( #LINES ) {
print FILE $LINE unless ( $LINE =~ m/$name/ );
}
close( FILE );
print( "Reservation successfully removed.<br/>" );
}
A couple of other things to note:
1) Your sample code calls removeReservation() when you mean removeTime()
2) You don't require the round brackets in your subroutine definition unless your intention is to use prototypes. See my example above.
This is in the FAQ.
How do I change, delete, or insert a line in a file, or append to the beginning of a file?
It's always worth checking the FAQ.
Just in case someone wants to remove all lines from a file.
For example, a file (4th line is empty; 5th line has 3 spaces):
t e st1
test2 a
e
aa
bb bb
test3a
cc
To remove lines which match a pattern some might use:
# Remove all lines with a character 'a'
perl -pi -e 's/.*a.*//' fileTest && sed -i '/^$/d' fileTest;
The result:
t e st1
e
bb bb
cc
Related:
perl -h
# -p assume loop like -n but print line also, like sed
# -i[extension] edit <> files in place (makes backup if extension supplied)
# -e program one line of program (several -e's allowed, omit programfile)
sed -h
# -i[SUFFIX], --in-place[=SUFFIX]
# edit files in place (makes backup if SUFFIX supplied)
Reference 1, Reference 2