bichonfrise74 has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

I have a text file and I want to insert some text at the start of the file. The text file would look like something below.
echo hello echo world echo I'm done.

I have seen people do it in the manner... this is from the link -

http://forums.macosxhints.com/archive/index.php/t-74203.html

I was wondering if there is a Perl way of insert text at the start of the file without doing any renaming of the file.

Also, the awk / sed methods look nice, but I'm not sure what is the counterpart of that in Perl.
# echo "" > temp # cat yourfile >> temp # mv temp yourfile the awk way: awk 'BEGIN{print "new text"}1' file the sed way sed -e '1i new line' file

Replies are listed 'Best First'.
Re: Elegant Way of Inserting Text at the Start of the File
by ikegami (Patriarch) on Nov 19, 2008 at 01:19 UTC

    Very similar to awk:

    perl -ple'BEGIN { print "new text" }' infile > outfile
    perl -i -ple'BEGIN { print "new text" }' file

    perlrun

      Hi,

      Thanks! But I want to insert this "code" into a script...

      Eg. Something like this...

      #!/usr/bin/perl while (<>) { BEGIN { print "Hello\n"; } print $_; } Then print Hello as the first line of text in a file.
      So, this will print the Hello as the first line, but it means that I have to open the file, output the result to a new file, delete the old file, and rename the new file as the old file.

      I was thinking if there is a way to just print "hello" straight to the file and incorporating it in a script?
        The "BEGIN" block will always be executed when the script is loaded and before the first (non-BEGIN) instruction is executed. It doesn't matter where the "BEGIN" block is positioned in the code -- inside or outside the while loop makes no difference -- it will only be executed once.

        In order to add content at the beginning of any disk file while preserving all the original content, there really is no practical way other than to create a new file, put the newly added content at the beginning of that new file, then copy/append the contents of the existing file, then rename the new one to replace (delete) the old one.

        If you want to replace the initial portion of a file (or even any non-initial portion) while preserving the portion(s) that you don't replace, that can be done, but you have to be certain that the new data being put in has the exact same byte-count as the data being replaced.

        In other words, anything that involves moving the "preserved" content to a different byte offset (relative to the beginning of the file) is best done by writing a new version of the file to replace the old one.

        So, this will print the Hello as the first line, but it means that I have to open the file, output the result to a new file, delete the old file, and rename the new file as the old file.

        Yes, you will have to do some variation of that. Like I said earlier, it's impossible to insert into a file.

        The most straightforward alternative is to load the file into memory, seek to the start of the file, then output the modified file. I guess that's where ig's code is useful.


        i think you can use in-place edit to add lines anywhere in the file provided you know the line number for addition.
        the below code will add Hello in first line of file.
        #!/usr/bin/perl use warnings; use strict; my $string="Hello"; { local @ARGV = ("$ARGV[0]"); local $^I = '.bac'; while(<>){ if ($. == 1) { # if line no is 1 print "$string$/"; print; # Also print the current line } else { print; } } }

        if you name it edit.pl , then calling edit.pl <filename> will do the job.
        you can customize other stuff in the program, i just expressed idea.
        may be Monks can comment if its the right way or not, iam still a beginner and learner
Re: Elegant Way of Inserting Text at the Start of the File
by Util (Priest) on Nov 19, 2008 at 01:20 UTC

    Either of these:

    perl -i -wpe 'print "new text\n" if $. == 1;' file
    perl -MTie::File -we 'tie @L, "Tie::File", "file" or die; unshift @L, +"new text";'
    See perlrun for the meanings of the command-line flags.

Re: Elegant Way of Inserting Text at the Start of the File
by swampyankee (Parson) on Nov 19, 2008 at 02:12 UTC

    You could probably do it with Tie::File.


    Information about American English usage here and here. Floating point issues? Please read this before posting. — emc

Re: Elegant Way of Inserting Text at the Start of the File
by oko1 (Deacon) on Nov 19, 2008 at 02:36 UTC

    A few slightly different methods:

    perl -0i -wpe's/^/new line\n/' file perl -0i -wpe'substr $_,0,0,"new line\n"' file perl -i -wlpe'print "new line" if 1..1' file

    All of the above assume (much like some of the ideas suggested by other people here) that the file already has some content; they will not work if it's completely empty.


    --
    "Language shapes the way we think, and determines what we can think about."
    -- B. L. Whorf
Re: Elegant Way of Inserting Text at the Start of the File
by Lawliet (Curate) on Nov 19, 2008 at 01:21 UTC

    Perhaps open the file for appendation (noun form of append :P) and seek to the beginning of the file. Then just print FILEHANDE "new text";

    May not be that elegant, though. :\

    Update: Don't know what I am talking about - I just assumed that I did :D.

    I'm so adjective, I verb nouns!

    chomp; # nom nom nom

      That won't insert. You can't insert into a file. You need to move everything that comes afterwards yourself.

      My test (Windows and linux) shows it still appends despite the seek.

      >copy con file foo bar ^Z 1 file(s) copied. >perl -le"open my $fh, '>>', 'file' or die $!; seek $fh, 0, 0 or die $ +!; print $fh 'baz';" >type file foo bar baz

        You can use '+<' to open the file for read and write without truncating. Then seek does work and the print overwrites the beginning of the file.

        $ echo -ne "foo\nbar\n" > file $ cat file foo bar $ perl -le'open my $fh, "+<", "file" or die $!; seek $fh, 0, 0 or die +$!; print $fh "bazz";' $ cat file bazz ar
Re: Elegant Way of Inserting Text at the Start of the File
by JavaFan (Canon) on Nov 19, 2008 at 12:24 UTC
    If the file you want to edit is very large (too large to suck the file comfortable into memory), and for some reason you don't want (or cannot) use a temporary file, you may want to do something like:
    use Fcntl ':seek'; my $file_name = "..."; my $buffer = <<'EOT'; echo hello echo world echo I'm done. EOT open my $fh, "+<", $file_name or die $!; my $r = 4096; while ($r = sysread $fh, $buffer, $r, length $buffer) { seek $fh, -$r, SEEK_CUR or die $!; syswrite $fh, substr $buffer, 0, $r, "" or die $!; } die $! unless defined $r; syswrite $fh, $buffer or die $!; close $fh or die $!;
    The code above uses a fixed amount of memory, independent of the size of the file. You may want to do add a loop around syswrite if you think it may not write the entire chunk at once.
Re: Elegant Way of Inserting Text at the Start of the File
by matrixmadhan (Beadle) on Nov 19, 2008 at 06:02 UTC
    apart from awk/sed the same can be done using ex also