From: divyajacob on
I was trying out a program
Accept a filename as command line argument. Display the
contents of that file in the opposite order that they appear in the
file.

file content is :-

Three Rings for the Elven-kings under the sky,
Seven for the Dwarf-lords in their halls of stone,
Nine for Mortal Men doomed to die,
One for the Dark Lord on his dark throne
In the Land of Mordor where the Shadows lie.
One Ring to rule them all, One Ring to find them,
One Ring to bring them all and in the darkness bind them
In the Land of Mordor where the Shadows lie.


I want to print it like:-

In the Land of Mordor where the Shadows lie.
One Ring to bring them all and in the darkness bind them
One Ring to rule them all, One Ring to find them,
In the Land of Mordor where the Shadows lie.
One for the Dark Lord on his dark throne
Nine for Mortal Men doomed to die,
Seven for the Dwarf-lords in their halls of stone,
Three Rings for the Elven-kings under the sky,

The program I wrote is
use strict;
my $num = $#ARGV + 1;
my $str;
my @file;
if($num >= 1)
{
$str = $ARGV[0];
}
else
{
print "No argument provided\n";
}

open (FILE,$str);
while(<FILE>)
{
push(@file,$_);
}
print "Reversed file content\n";
foreach(@file)
{

print pop(@file);
}
O/p
perl ex_04.pl ringfile.txt
Reversed file content
In the Land of Mordor where the Shadows lie.
One Ring to bring them all and in the darkness bind them
One Ring to rule them all, One Ring to find them,
In the Land of Mordor where the Shadows lie.

I am getting only 4 lines in the output,Why I am not getting full 8
lines in the output?
Please help..am I doing anything wrong.

Thanks in advance
Divya

From: J�rgen Exner on
divyajacob <divyajacobpulickal(a)gmail.com> wrote:
>I was trying out a program
> Accept a filename as command line argument. Display the
>contents of that file in the opposite order that they appear in the
>file.
>
>file content is :-
>
>Three Rings for the Elven-kings under the sky,
>Seven for the Dwarf-lords in their halls of stone,
>Nine for Mortal Men doomed to die,
>One for the Dark Lord on his dark throne
>In the Land of Mordor where the Shadows lie.
>One Ring to rule them all, One Ring to find them,
>One Ring to bring them all and in the darkness bind them
>In the Land of Mordor where the Shadows lie.
>
>
>I want to print it like:-
>
>In the Land of Mordor where the Shadows lie.
>One Ring to bring them all and in the darkness bind them
>One Ring to rule them all, One Ring to find them,
>In the Land of Mordor where the Shadows lie.
>One for the Dark Lord on his dark throne
>Nine for Mortal Men doomed to die,
>Seven for the Dwarf-lords in their halls of stone,
>Three Rings for the Elven-kings under the sky,
>
>The program I wrote is
>use strict;
>my $num = $#ARGV + 1;

Better (unless you fooled around with $[ )
my $num = @ARGV;
# using an array in scalar context yields the number of array elements

>my $str;
>my @file;
>if($num >= 1)

More perlishly written as
if (@ARGV) {
# yields false if and only if array length is 0

>{
> $str = $ARGV[0];
>}
>else
>{
> print "No argument provided\n";

Logical error. Probably missing:
exit -1;
Otherwise you continue your program and try to open a file even if there
was no filename supplied.
>}

>open (FILE,$str);

You should use lexical file handles, the 3-argument form of open(), and
always, yes always, check for failure:
open ($FILE, '<', $str) or die "Cannot open $str: $!";

>while(<FILE>)
>{
> push(@file,$_);
>}

The whole while loop can be replaced by
@file = <$FILE>;

>print "Reversed file content\n";
>foreach(@file) {
> print pop(@file);
>}

This is bad bad bad style. While looping through the array using foreach
you are altering the array itself, i.e. you are deleting elements from
the array. Don't do that because results are unpredictable.

In this case by the time the loop has been executed 4 fimes the array
contains only 4 remaining elements and the foreach loop has reached the
end of the array.

Instead use a while loop:
while (@file) {
This will repeat the loop until all elements have been pop'ed out of the
array and only the empty array is left.

And of course the most obvious approach is to use reverse().

print reverse (@file);

jue
From: Tad McClellan on
divyajacob <divyajacobpulickal(a)gmail.com> wrote:
> I was trying out a program
> Accept a filename as command line argument. Display the
> contents of that file in the opposite order that they appear in the
> file.

> The program I wrote is
> use strict;
> my $num = $#ARGV + 1;


my $num = @ARGV;


> open (FILE,$str);


You should always, yes *always*, check the return value from open():

open(FILE, $str) or die "could not open '$str' $!";


> foreach(@file)
> {
>
> print pop(@file);

> I am getting only 4 lines in the output,Why I am not getting full 8
> lines in the output?
> Please help..am I doing anything wrong.


Yes, what you are doing wrong is not reading the docs for
the language features that you are using.

The "Foreach Loops" section in

perldoc perlsyn

says

If any part of LIST is an array, foreach will get very confused if
you add or remove elements within the loop body, for example with
splice. So don't do that.

so then,

while (@file) {
print pop(@file);
}

or, probably better

foreach (reverse @file) {
print;
}

or, probably better still, simply

print reverse <FILE>;


--
Tad McClellan
email: perl -le "print scalar reverse qq/moc.liamg\100cm.j.dat/"
The above message is a Usenet post.
I don't recall having given anyone permission to use it on a Web site.
From: Ben Morrow on

Quoth divyajacob <divyajacobpulickal(a)gmail.com>:
> I was trying out a program
> Accept a filename as command line argument. Display the
> contents of that file in the opposite order that they appear in the
> file.
>
> file content is :-
>
> Three Rings for the Elven-kings under the sky,
> Seven for the Dwarf-lords in their halls of stone,
> Nine for Mortal Men doomed to die,
> One for the Dark Lord on his dark throne
> In the Land of Mordor where the Shadows lie.
> One Ring to rule them all, One Ring to find them,
> One Ring to bring them all and in the darkness bind them
> In the Land of Mordor where the Shadows lie.
>
>
> I want to print it like:-
>
> In the Land of Mordor where the Shadows lie.
> One Ring to bring them all and in the darkness bind them
> One Ring to rule them all, One Ring to find them,
> In the Land of Mordor where the Shadows lie.
> One for the Dark Lord on his dark throne
> Nine for Mortal Men doomed to die,
> Seven for the Dwarf-lords in their halls of stone,
> Three Rings for the Elven-kings under the sky,
>
> The program I wrote is
> use strict;

Good. You also want

use warnings;

> my $num = $#ARGV + 1;

If you want the number of elements in an array, evaluate the array in
scalar context. That is:

my $num = @ARGV;

(You don't actually need $num at all: if (@ARGV >= 1) will work
perfectly well.)

> my $str;
> my @file;
> if($num >= 1)
> {
> $str = $ARGV[0];
> }
> else
> {
> print "No argument provided\n";
> }

If there is no argument provided, this will print a message and then
carry on regardless. You probably want to replace 'print' with 'die',
which will print the message to STDERR (as appropriate for errors) and
then exit.

>
> open (FILE,$str);

*Always* check the return value of open, or use 'autodie' which will do
it for you.
Use 3-arg open (it's safer, especially when you don't know what the
filename will be).
Use lexical filehandles.

open(my $FILE, "<", $str)
or die "can't open '$str': $!";

> while(<FILE>)
> {
> push(@file,$_);
> }

<FILE> will return the whole file, divided into lines, if you use it in
list context, so this whole loop can be replaced with

my @file = <$FILE>;

> print "Reversed file content\n";
> foreach(@file)
> {
>
> print pop(@file);
> }

If you have just a single array as the argument to foreach, perl will
iterate over the array itself rather than expanding it to a list first.
This means that if you modify the array in the loop you will see
unexpected side-effects. You want either

foreach (reverse @file) {
print $_;
}

or

while (@file) {
print pop @file;
}

Ben

From: sln on
On Mon, 14 Jun 2010 05:30:27 -0700 (PDT), divyajacob <divyajacobpulickal(a)gmail.com> wrote:

>I was trying out a program
> Accept a filename as command line argument. Display the
>contents of that file in the opposite order that they appear in the
>file.
>
[snip]
>foreach(@file)
>{
>
>print pop(@file);
>}
[snip]

>I am getting only 4 lines in the output,Why I am not getting full 8
>lines in the output?
>Please help..am I doing anything wrong.
>
>Thanks in advance
>Divya

The only question is why the bogus pretense of programming.
Are you trying to actually print out a reverse of the file
or are you whining that this:

print pop(@array) foreach(@array)

never works?

How do you know what pop, push, foreach is ??
What does print pop(@array) do?
You have to go to the root of the problem.

-sln