0

I need to read only the last line of a file, without using File:ReadBackwards module as it is not installed on my remote server(windows) where I need to execute the script. Kindly suggest the most efficient way to read only the last line.

simbabque
  • 53,749
  • 8
  • 73
  • 136
STJ
  • 39
  • 1
  • 7
  • Take a look at http://stackoverflow.com/questions/187587/looking-for-a-windows-equivalent-of-the-unix-tail-command#comment5036679_187826 – simbabque Apr 12 '16 at 11:39
  • The most efficient way is to install the module that you're missing. – Dave Cross Apr 12 '16 at 13:01
  • @DaveCross Thanks and I understand too but that is a remote server, not totally handled by me. – STJ Apr 14 '16 at 10:03
  • @simbabque sure that post make sense. But if I could have installed anything on machine I would have done the module itself – STJ Apr 14 '16 at 10:13
  • My link didn't point to any answer, but one specific comment that gives you a batch file. – simbabque Apr 14 '16 at 10:16
  • @simbabque thats cool, Thanks, Will try that too. I thought you pointed to the marked answer of that question which said about installing GNU utilities. Sorry about that. Thanks again. – STJ Apr 14 '16 at 10:23
  • Nope. Linking to comments is a bit weird, but it appears at the very top of the browser. – simbabque Apr 14 '16 at 10:30

4 Answers4

7

This answer does not work on Windows.


If this is a one-off thing, simply do a system call and use tail.

my $last_line = `tail -n 1 $filename`;

If you need to do this a lot, think about installing into a local-lib on the remote machine, or fatpacking File::ReadBackwards into your script before you deploy it.

simbabque
  • 53,749
  • 8
  • 73
  • 136
  • Haha, it looks like we were typing the same answer at the same time. Nice call with the fatpacking. – themattkellyshow Apr 12 '16 at 08:59
  • 1
    @MattKelly actually no, this is a different solution from yours. Backticks are not the same a `system`. – simbabque Apr 12 '16 at 09:00
  • You could also use the `qx` operator e.g. `my $last_line = qx!tail -n 1 $filename!;` – dgw Apr 12 '16 at 09:40
  • @simbabque I am getting below error, please suggest: 'tail' is not recognized as an internal or external command, operable program or batch file. – STJ Apr 12 '16 at 09:47
  • 1
    @STJ tail command for linux not for windows. So it shows `tail' is not recognized as an internal or external command` – mkHun Apr 12 '16 at 10:10
  • Ohh, I missed the basic in trouble. Please answer this question for windows. – STJ Apr 12 '16 at 10:22
  • I would expect windows with the cygwin and/or posix environments to support "tail" – Sherwood Botsford Apr 19 '21 at 13:05
1

You are in windows. I don't know what are the inbuild command for windows but you try something like as follows

Iterate the file handler with while loop and store the output in variable then print it

open my $fh ,"<","file.txt";
my $last_line;
$last_line = $_,while (<$fh>);
print $last_line;

or else try the follow but these are consume more memory.

open my $fh ,"<","file.txt" or die "error opening $!";
my @ar = <$fh>;
print $ar[-1];

Or else

open my $fh ,"<","file.txt" or die "error opening $!";
my @ar = <$fh>;
print pop @ar;
mkHun
  • 5,891
  • 8
  • 38
  • 85
  • 2
    Reading the whole file into an array, just to pop the last line seems wasteful to me. – Sobrique Apr 12 '16 at 10:27
  • @Sobrique Yep its correct it is more memory consume. I give the other option by using while loop. – mkHun Apr 12 '16 at 10:34
  • @mkHun Thanks, along with getting expected output, using file handler is effective too. – STJ Apr 14 '16 at 10:01
0

If you know something about the files (if the lines are relatively equal lengths, or if each line is at most X bytes, or whatever) you might be able to do something with seek. For example, if the last line is at most 40 bytes or so, you can do the below. If you know the file is 100 MB (using File::stat, which is core) you could average the first 10 lines and see how many bytes they are, and maybe multiply that by 5 just in case and seek back that far and then do the loop. You might have to read 15 or 20 lines, but that's not bad.

open(my $input,"input2.txt")||die "can't open the file";

my $last_line;
seek ($input, -50, 2);
while(<$input>)
{
    $last_line = $_;
}

print "$last_line\n";
kchinger
  • 339
  • 2
  • 10
  • Try to use lexical file handle. – mkHun Apr 16 '16 at 04:30
  • @mkHun I'm not sure what you mean. $input _is_ a lexical file handle. – kchinger Apr 16 '16 at 04:38
  • Lexical file handle have thee arguments. `open my $fh,"<","filename";`. The reason of the lexical file handle is, no need to close the file. – mkHun Apr 16 '16 at 04:40
  • @mkHun That's not what lexical file handle means. Lexical just means not global in scope, which my $input is. The second argument is optional. It's perfectly valid and correct Perl. http://perldoc.perl.org/functions/open.html – kchinger Apr 16 '16 at 04:43
-1

I found the following here.

Try this on for size:

system tail => -1 => $file;
  • 7
    `system` [returns the exit code](http://perldoc.perl.org/functions/system.html) of the program it runs, **not the output**. – simbabque Apr 12 '16 at 08:59