I have a problem about arithmetic expression in Perl.
I have already written the code but I couldn't fill inside of eval function.
Example:
>2+4
6
Another example:
>8-2*2
4
This is my program
#!/usr/bin/perl
print ">";
while (<>) {
eval(---------);
print "\n>";
}
You can chomp the input to remove the newline and use string eval.
#!/usr/bin/perl
print ">" ;
while (<>) {
chomp $_;
my $result = eval $_;
print "$result\n>";
}
Think about this: What happens when someone enters `rm *` at the prompt?
You aren't printing the result of eval. The calculation is being done, but you are just throwing it away and printing another prompt.
This should do as you want.
#!/usr/bin/perl
print ">" ;
while (<>) {
print eval, "\n>";
}
You can just write in that way:
#!/usr/bin/perl
print ">";
while (<>) {
print eval("$_");
print "\n>";
}
Related
I am writing a script in Perl where I have to open the same file twice in my code. This is my outline of the code:
#!/usr/bin/perl
use strict;
use warnings;
my %forward=();
my %reverse=();
while(<>){
chomp;
# store something
}
}
while(<>){ # open the same file again
chomp;
#print something
}
I am using the diamond operator so I am running the script like this
perl script.pl input.txt
But this is not producing any output. If I open the File using filehandle, the script works. What can be possibly wrong here?
Save your #ARGV before exhausting it. Of course, this will only work for actual files specified on the command line, and not with STDIN.
#!/usr/bin/env perl
use strict;
use warnings;
run(#ARGV);
sub run {
my #argv = #_;
first(#argv);
second(#argv);
}
sub first {
local #ARGV = #_;
print "First pass: $_" while <>;
}
sub second {
local #ARGV = #_;
print "Second pass: $_" while <>;
}
You read all there was to be read in the first loop, leaving nothing to read in the second.
If the input aren't huge, you can simply load it into memory.
my #lines = <>;
chomp( #lines );
for (#lines) {
...
}
for (#lines) {
...
}
I am a beginner to perl and have just been messing around trying to create little scripts. I'm not sure what is wrong here but it just falls through to the else every time as if nothing I input satisfies the if or elsif conditions. Is it because eq is the wrong operator? Or is there something else wrong in my code? Thanks!
#!/usr/bin/perl
use strict;
use warnings;
print "what is your name?\n";
my $name = readline STDIN;
print "Hello $name How are you today?\n";
my $feeling = readline STDIN;
if ($feeling eq "happy") {
print "that's good!\n";
}
elsif ($feeling eq "good") {
print "okay!\n";
}
else {
print "Interesting\n";
}
Use chomp($feeling);
#!/usr/bin/perl
use strict;
use warnings;
print "what is your name?\n";
my $name = readline STDIN;
chomp($name);
print "Hello $name How are you today?\n";
my $feeling = readline STDIN;
chomp($feeling);
if ($feeling eq "happy") {
print "that's good!\n";
}
elsif ($feeling eq "good") {
print "okay!\n";
}
else {
print "Interesting\n";
}
readline STDIN captures every character typed along with last enter hit as \n, say if you type "happy" and hit enter for $feeling then its accepted as "happy\n" notice \n is because enter hit to remove last \n newline character use chomp removes any trailing string
chomp is used to "chomp off" the input record separator, which by default is a newline character.
#!/usr/bin/perl
use strict;
use warnings;
use 5.012; # to use things like 'say' and 'given'
say "what is your name?"; # 'say' is like 'print', but means you don't have to use '\n'
my $name = <STDIN>; # good to include angled brackets <>
chomp($name); # remove the newline when entering the number
say qq{Hello $name, how are you today?}; # qq{} acts like double-quotes ("")
my $feeling = <STDIN>;
chomp $feeling; # notice parenthese aren't always needed
# you could also do chomp(my $feeling=<STDIN>);
given (lc $feeling){ # 'given' is Perl's version of a Switch and lc makes input lowercase
when('happy') { say q{That's good.} } # q{} acts like single-quotes ('')
when('good') { say q{Okay!} }
default { say q{Interesting} } # your else-case
}
As the warnings suggest, given is experimental until smartmatch is figured out. It is perfectly acceptable to use the if-elsif-else structure, if you choose.
I'm trying to edit a text using Perl. I need to make a substitution but the substitution cannot be applied once an specific word is found in the text. So, imagine I want to substitute all the "hello" forms by "goodbye", but the substitution cannot be applied once the word "foo" is found.
I tried to do this:
use warnings;
use strict;
$/ = undef;
my $filename = shift;
open F, $filename or die "Usa: $0 FILENAME\n";
while(<F>) {
do {s/hello/goodbay/} until (m{foo});
print;
}
close F;
But, as a result, only the first "hello" of my text is changed.
Any suggestion?
Trying to think what would be the most efficient. It should be one of the following:
s{^(.*?)(foo|\z)}{
my $s = $1;
$s =~ s{hello}{goodbay}g;
$s.$2
}se;
print;
or (same as above, but requires 5.14+)
s{^(.*?)(foo|\z)}{ s{hello}{goodbay}gr . $2 }se;
print;
or
my $pos = /foo/ ? $-[0] : length;
my $s = substr($_, 0, $pos, '');
$s =~ s{hello}{goodbay}g;
print($s);
print;
Both work even if foo isn't present.
This solution uses less memory:
# Assumes foo will always be present
# (though it could be expanded to handle that
# Assumes foo isn't a regex pattern.
local $/ = "foo";
$_ = <$fh>;
chomp;
s{hello}{goodbay}g;
print;
print $/;
local $/;
print <$fh>;
If the substrings you work on (the hello and foo of your example) are single words, a easy way would probably be to replace $/ = undef; with $/ = " ";. Currently you slurp in the whole file at once, meaning the while loop gets executed at most once.
That is because there is only one "line" in the whole input after you told perl that there are no line separators.
If you use a space as input separator, it will loop over the input word by word and hopefully work as you intend.
Use a flag variable:
use warnings;
use strict;
my $filename = shift;
open F, $filename or die "Usa: $0 FILENAME\n";
my $replace=1;
while(<F>) {
$replace = 0 if m{foo};
s/hello/goodbye/g if $replace;
print;
}
close F;
This stops at the line containing the end pattern. It will be slightly more complicated if you want to substitute up to just before the match.
This answer uses the ${^PREMATCH] and related variables introduced in Perl 5.10.
#!/usr/bin/env perl
use v5.10.0;
use strict;
use warnings;
my $foo_found;
while (my $line = <>) {
if (!$foo_found) {
if ($line =~ m/foo/ip) {
# only replace hellos in the part before foo
${^PREMATCH} =~ s/hello/goodbye/g;
$line = "${^PREMATCH}${^MATCH}${^POSTMATCH}";
$foo_found ++;
} else {
$line =~ s/hello/goodbye/ig;
}
}
print $line;
}
Given the following input:
hello cruel world
hello baseball
hello mudda, hello fadda
foo
The rest of the hellos should stay
Last hello
I get the following output
goodbye cruel world
goodbye baseball
goodbye mudda, goodbye fadda
foo
The rest of the hellos should stay
Last hello
If you don't have 5.10 you can use $` and related variables but they come with a performance hit. See perldoc perlvar for details.
How to read multiple lines from console in Perl?
I have used #a = <STDIN>; but I am unable to come out of that statement. Evertime I hit enter it goes to new line. I have read to hit ctrl+d to end the input but it does not seem to work.
Maybe a better idea would be a loop of some sort:
use strict;
use warnings;
my #a;
for(;;) {
my $input = <STDIN>;
last if not defined $input;
chomp $input;
push #a, $input;
}
This will end when you type in the Unix <EOF> (which is usually set to Ctrl-D by default).
You can use while loop,
my #a;
while (<STDIN>) {
/\S/ or last; # last line if empty
push #a, $_;
}
print #a;
It seems like you are on Windows. On Windows you have to hit Control-z on an empty line and then hit Enter.
I already did some research on Perl script debugging but couldn't find what I was looking for.
Let me explain my problem here.
I have a Perl script which is not entering into last while loop it seems cos it is not printing anything inside as instructed.
So, I want to know is there any easier method available to see all lines one by one like we can see in shell script using
set -x
Here is my Perl script code
#!/usr/bin/perl -w
my $ZONEADM = "/usr/sbin/zoneadm list -c";
use strict;
use diagnostics;
use warnings;
system("clear");
print "Enter the app\n";
chomp(my $INS = <>);
print "\nEnter the Symmitrix ID\n";
chomp(my $SYMM = <>);
print "\nEnter the Server\n";
chomp(my $SRV = <>);
print "\nEnter the devices\n";
while (<>) {
if($_ !~ m/(q|quit)/) {
chomp($_);
my $TEMP_FILE = "/export/home/ptiwari/scripts/LOG.11";
open (my $FH, '>>', $TEMP_FILE);
my #arr = split(/:/, $_);
if($arr[3]) {
print $FH "/".$INS."db/".$arr[0]." ".$SYMM." ".$arr[1]." ".$arr[2]." ".$arr[3]."\n";
}
else {
print $FH "/".$INS."db/".$arr[0]." ".$SYMM." ".$arr[1]." ".$arr[2]."\n";
}
undef #arr;
close $FH;
}
else {
exit;
}
}
my $IS_ZONE = qx($ZONEADM|grep -i $SRV|grep -v global);
if($IS_ZONE) {
$IS_ZONE = "yes";
}
else {
$IS_ZONE = "no";
}
open(my $FLH, '<', "/export/home/ptiwari/scripts/LOG.11");
my #lines;
while(<$FLH>) {
my ($GLOBAL_MTPT, $SYM, $SYM_DEV, $SIZE, $NEWFS) = split;
print $GLOBAL_MTPT." ".$SYM." ".$SYM_DEV;
print "\n";
}
I already tried perl -d but it didn't show me anything which can help me to troubleshoot why it didn't enter the while loop.
Your while(<>) loop doesn't have sensible termination conditions. The /q|quit/ regex is buggy.
You exit the whole script if any line contains q or quit. You will also exit, if the device descriptions contains things like quill or acquisition. The effect of typing an accidental q is similar to a CtrlC.
The only way to finish the loop and go on with the script is to send an EOF. This requires the user to punch CtrlD into the keyboard, or a file to simply end. Then your script will continue.
There are some other things wrong/weird with this script.
Main criticism: (a) all-uppercase variables are informally reserved for Perl and pragmatic modules. Lowercase or mixed case variables work too. (b) Your script contains quite some redundant code. Either refactor it into subs, or rewrite your logic
Here is an example rewrite that may be easier to debug / may not contain some of the bugs.
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
use constant DEBUG_FLAG => 1; # set to false value for release
my $zoneadm_command = "/usr/sbin/zoneadm list -c";
my $temp_file_name = "/export/home/ptiwari/scripts/LOG.11";
sub prompt { print "\n", $_[0], "\n"; my $answer = <>; chomp $answer; return $answer }
sub DEBUG { print STDERR "DEBUG> ", #_, "\n" if DEBUG_FLAG }
system("clear");
my $app_name = prompt("Enter the app");
my $symm_id = prompt("Enter the Symmitrix ID");
my $server = prompt("Enter the server name");
print "Enter the devices.\n";
print qq(\tTo terminate the script, type "q" or "quit".\n);
print qq(\tTo finish the list of devices, type Ctrl+D.\n);
open my $temp_file, ">>", $temp_file_name
or die "Can't open log file: $!";
while (<>) {
chomp; # remove trailing newline
exit if /^q(?:uit)?$/; # terminate the script if the input line *is* `q` or `quit`.
my #field = split /:/;
# grep: select all true values
#field = grep {$_} ("/${app_name}db/$field[0]", $symm_id, #field[1 .. 3]);
print $temp_file join(" ", #field), "\n";
}
close $temp_file;
DEBUG("finished the reading loop");
# get the zones with only *one* extra process
my #zones =
grep {not /global/}
grep {/\Q$server\E/i}
map {chomp; $_}
qx($zoneadm_command);
my $is_zone = #zones ? "yes" : "no";
DEBUG("Am I in the zone? $is_zone");
open my $device_file, "<", $temp_file_name or die "Can't open $temp_file_name: $!";
while (<$device_file>) {
chomp;
my ($global_mtpt, $sym, $sym_dev) = split;
print join(" ", $global_mtpt, $sym, $sym_dev), "\n";
# or short: print join(" ", (split)[0 .. 2]), "\n";
}
You need something like this for stepping into the script:
http://www.devshed.com/c/a/Perl/Using-The-Perl-Debugger/
You can really use the debugger: http://perldoc.perl.org/perldebug.html
But if your preference is to trace like bash -x, take a look at this discussion:
http://www.perlmonks.org/?node_id=419653
The Devel::Trace Perl module is designed to mimic sh -x tracing for shell programs.
Try to remove the "my $" from the last open statement and the "$" from there in the last while statement. Or better yet, try this:
open(my FLH, '<', "/export/home/ptiwari/scripts/LOG.11");
my #lines = <FLH>;
foreach (#lines) {
my ($GLOBAL_MTPT, $SYM, $SYM_DEV, $SIZE, $NEWFS) = split;
print $GLOBAL_MTPT." ".$SYM." ".$SYM_DEV;
print "\n";
}
Let me know about the results.