Prompt user for input then add and subtract in the corresponding field [closed] - perl

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I want the variable $cpySold to be subtracted from $a[3] and added to $a[4]. How can I do it?
Currently my output is as follows:
Title:Alice in wonderland
Author:robert
No Of Copies Sold:*3*
Current Book Info:
Alice in wonderland, robert,$12.40,100,200
How do I do the line below? Assuming 100-3 =97, 100+3 = 103 after user entered 3 copies sold.
New Book Info: Alice in wonderland, robert,$12.40,97,203
function process_book_sold
{
read -p "Title: " title
read -p "Author: " author
read -p "No Of Copies Sold : " cpySold
if [ -n "$title" -a -n "$author" ]; then
perl -ne 'BEGIN{ $pattern = $ARGV[0]; shift;$pattern1 = $ARGV[0]; shift; $n=0 }
#a=split /:/;
if ($a[0] =~ m/$pattern/i and $a[1] =~ m/$pattern1/i)
{
print "Current Book Info: \n";
print "$a[0], $a[1],\$$a[2],$a[3],$a[4]\n";
}
END{ print "\n" }' "$title" "$author" /home/student/Downloads/BookDB.txt
fi
}

I don't like the mix of shell and Perl in the code, but that's apparently for pedagogical reasons so we have to ignore it.
process_book_sold()
{
read -p "Title: " title
read -p "Author: " author
read -p "No Of Copies Sold : " cpySold
if [ -n "$title" -a -n "$author" ]; then
perl -ne '
BEGIN{ $title = shift; $author = shift; $sales = shift; }
#a = split /:/;
if ($a[0] =~ m/$title/i and $a[1] =~ m/$author/i)
{
print "Current Book Info:\n";
print "$a[0], $a[1], $a[2], $a[3], $a[4]\n";
$a[3] -= $sales;
$a[4] += $sales;
print "New Book Info:\n";
print "$a[0], $a[1], $a[2], $a[3], $a[4]\n";
}
END{ print "\n" }' "$title" "$author" "$cpySold" /home/student/Downloads/BookDB.txt
fi
}
Apart from renaming pattern to title and pattern1 to author, this code passes the shell variable $cpySold to the Perl. It also uses a simpler method of retrieving the first three arguments (simply capture the value from shift). The split is the same as before. It isn't entirely clear what the format in the data file is since the printed formats use commas rather than colons to separate the fields.
I simply want the values from new book info to replace current book info in the BookDB.txt file.
I'm not convinced this is doing you any favours (you won't learn much unless you try doing it yourself), but ...
process_book_sold()
{
title="$1"
author="$2"
cpySold="$3"
if [ -n "$title" -a -n "$author" ]
then
perl -i -we '
use strict;
use English "-no_match_vars";
my $title = shift;
my $author = shift;
my $sales = shift;
while (<>)
{
chomp;
my #a = split /:/;
print STDERR "Debug: #a\n";
if ($a[0] =~ m/$title/i and $a[1] =~ m/$author/i)
{
print STDERR "Current Book Info:\n";
print STDERR "$a[0], $a[1], $a[2], $a[3], $a[4]\n";
$a[3] -= $sales;
$a[4] += $sales;
print STDERR "New Book Info:\n";
print STDERR "$a[0], $a[1], $a[2], $a[3], $a[4]\n";
$OFS = ":";
$ORS = "\n";
print #a;
}
}
' "$title" "$author" "$cpySold" BookDB.txt # /home/student/Downloads/BookDB.txt
fi
}
# read -p "Title: " title
# read -p "Author: " author
# read -p "No Of Copies Sold : " cpySold
process_book_sold "Alice in Wonderland" "Carroll" "3"
This doesn't pester me with typing the title, author or number of copies sold. You can reinstate those lines if you wish, but the function is probably more useful if it takes the arguments. (It is often good to separate user interaction from code that operates on files.) I've used the correct author name (unless you want to use Dodgson as the real name of the author who used the pseudonym Lewis Carroll). The Perl script uses the -i option to overwrite the input files. It uses the English module so it can set $OFS and $ORS. It writes debug information to STDERR (otherwise, it would be part of the information written to the file).
When the file was called pbs2.sh, a sample run of the script looked like:
$ cat BookDB.txt; bash pbs2.sh; cat BookDB.txt
Alice in Wonderland:Carroll:$12.40:74:226
Debug: Alice in Wonderland Carroll $12.40 74 226
Current Book Info:
Alice in Wonderland, Carroll, $12.40, 74, 226
New Book Info:
Alice in Wonderland, Carroll, $12.40, 71, 229
Alice in Wonderland:Carroll:$12.40:71:229
$
Clearly, this wasn't the first time I'd run the script, and at times I used values other than 3 for the number of copies sold.
With explicit file management, you can write:
process_book_sold()
{
title="$1"
author="$2"
cpySold="$3"
if [ -n "$title" -a -n "$author" ]; then
perl -we '
use strict;
use English "-no_match_vars";
my $title = shift;
my $author = shift;
my $sales = shift;
my $file = shift;
open my $fh, "+<", $file or die "Failed to open file $file for reading and writing";
my $text;
{
local $/;
$text = <$fh>;
}
chomp $text;
my #a = split /:/, $text;
print "Debug: #a\n";
if ($a[0] =~ m/$title/i and $a[1] =~ m/$author/i)
{
print "Current Book Info:\n";
print "$a[0], $a[1], $a[2], $a[3], $a[4]\n";
$a[3] -= $sales;
$a[4] += $sales;
print "New Book Info:\n";
print "$a[0], $a[1], $a[2], $a[3], $a[4]\n";
seek $fh, 0, 0;
truncate $fh, 0;
$OFS = ":";
$ORS = "\n";
print $fh #a;
}
close $fh;
' "$title" "$author" "$cpySold" BookDB.txt # /home/student/Downloads/BookDB.txt
fi
}
# read -p "Title: " title
# read -p "Author: " author
# read -p "No Of Copies Sold : " cpySold
process_book_sold "Alice in Wonderland" "Carroll" "7"
Sample run:
$ cat BookDB.txt; bash pbs1.sh; cat BookDB.txt
Alice in Wonderland:Carroll:$12.40:50:250
Debug: Alice in Wonderland Carroll $12.40 50 250
Current Book Info:
Alice in Wonderland, Carroll, $12.40, 50, 250
New Book Info:
Alice in Wonderland, Carroll, $12.40, 43, 257
Alice in Wonderland:Carroll:$12.40:43:257
$

Related

Reversed Pyramid Design in Perl

I need to input a number of lines and a single character to use for the reverse pyramid.The output must look like the following:
Maximum number of characters in a line : 6
Enter Echo Character : $
$$$$$$
$$$$$
$$$$
$$$
$$
$
This is what I have so far:
print "Maximum number of characters in a line : ";
$size = <>;
print "Enter Echo Character : ";
$character = <>;
chomp($size);
Loop: for $row (1 .. $size)
{
for $column (1 .. ($size+1))
{
if ($column < $row)
{
print "\n";
next Loop;
}
print $character;
}
}
But I am definitely doing something wrong because I cannot get the output I need after a couple hours of trying. I am new at Perl and any help I can get is definitely appreciated.
KMBP:Assignment 13 mypc$ perl pyramidtest.pl
Maximum number of characters in a line : 6
Enter Echo Character : $
$
$
$
$
$
$
$
KMBP:Assignment 13 mypc$
The x operator is also useful for this.
use feature qw(say);
print 'character? ';
chomp(my $char = <STDIN>);
print 'length? ';
chomp(my $length = <STDIN>);
while ($length) {
say $char x $length;
$length--;
}
Why are you setting $row from 1 .. $size if you want a reverse pyramid?
Why are you setting the end of the range for $column to $size + 1 instead of $row?
Why do you have some kind of strange logic for determining when to print a newline?
use strict;
use warnings;
print "Maximum number of characters in a line : ";
chomp(my $size = <>);
print "Enter Echo Character : ";
chomp(my $character = <>);
while ($size) {
for (1 .. $size) {
print $character;
}
print "\n";
$size--;
}
Note: you probably want to validate that $size is a positive integer, or else you might get unexpected results for certain inputs!

How to validate a plain text file in perl [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have tried to use if statement with arguments like -e, -f and -T to check if a file exist, if it's a file and if it's a plain text file.
print "$_ is readable text\n" if -e $_ && $f $_ && -T $_;
But this won't work as expected: Some binary files is chown.
perl's heuristic test for determining if -B or -T
command perldoc -f -T | sed -ne '/-T.*"-B".*work/,+3p' output:
The "-T" and "-B" switches work as follows. The first block or
so of the file is examined for odd characters such as strange
control codes or characters with the high bit set. If too many
strange characters (>30%) are found, it's a "-B" file;
So if 30% don't match your need, you have to use another way:
Use Test::PureASCII
use Test::PureASCII tests => $how_many;
file_is_pure_ascii($filename1, "only ASCII in $filaname1");
or build your own test routine.
#!/usr/bin/perl -w -CIO
use strict;
sub testfile {
open FH, "<" . $_[0];
my $block = " " x 4096;
sysread FH, $block, 4096;
close FH;
return 0 unless $block =~ /^[\r\n\t -~]*$/s;
return 1;
}
opendir DH, "/tmp";
map {
printf "%s\n", $_;
} grep {
-f "/tmp/" . $_ &&
-r "/tmp/" . $_ &&
testfile "/tmp/" . $_;
} readdir DH;
Same, accepting UTF-8
#!/usr/bin/perl -w -CIO
use strict;
use utf8;
sub testfile {
open FH, "<" . $_[0];
my $block = " " x 16384;
sysread FH, $block, 16384;
close FH;
utf8::decode $block if utf8::valid($block);
return 0 unless $block =~ /^([\r\n\t -~]|\p{Latin})*$/s;
return 1;
}
opendir DH, "/tmp";
map { printf "%s\n", $_ } grep { -f "/tmp/" . $_ && -r "/tmp/".
$_ && testfile "/tmp/" . $_; } readdir DH;
you can use
if(-f "filename" ) {
#validate content if required
#do other things
}
if you want to validate the content of file, you'll have to code that logic yourself before you do other things.
For more details read http://perldoc.perl.org/functions/-X.html.

print only one/desired value in for/foreach loop

I have part of the code (program which needs to calculate sum of open files on system for specified users):
for my $opt_u (#opt_u){
my $generic_acc_open = `/usr/sbin/lsof -u $opt_u | /usr/bin/wc -l`;
chomp ($generic_acc_open);
#print "$open";
print "Number of open files for users:$opt_u[0]=$generic_acc_open**$opt_u[1]=$generic_acc_open\n;"
}
where opt_u is argument for users specified on cli.
My problem is when i run a program (./proc_limit -u root jenkins) i am getting output like this:
Number of open files for users:root=85**jenkins=85
;Number of open files for users:root=13**jenkins=13
I am trying to get output in one line, probably it is not possible because array is specified with arguments in this case two times(for two users). Is it possible with for/foreach loop or i should use something else to get output in one line like this:
Number of open files for users:root=85**jenkins=13
You're currently trying to print out results for two different queries using the same variable, $generic_acc_open.
You need to get the results for each user and store them separately. Here's one possible way to do it that will work for any number of users:
print "Number of open files for users: ",
join(" ** ",
map { my $n = `/usr/sbin/lsof -u $_ | /usr/bin/wc -l`;
$n =~ s/\s+//g;
"$_ = $n"
} #opt_u ), "\n";
Output:
Number of open files for users: anonymous = 5548 ** jenkins = 42 ** root = 0
Explanation:
print "Number of open files for users: ",
# join every member of the array with " ** "
join(" ** ",
# map applies the expressions within the braces to each member of the array #opt_u
# map produces an array as output, which is acted upon by the join function
map {
# get number of open files for user $_
my $n = `/usr/sbin/lsof -u $_ | /usr/bin/wc -l`;
# remove whitespace from the answer
$n =~ s/\s+//g;
# print out the user, $_, and the number of open files, $n
"$_ = $n" } #opt_u ),
"\n";
To print the total number of files, keep a tally of how many files are open and print it at the end of the line:
my $sum;
print "Number of open files for users: ",
join(" ** ",
map { my $n = `/usr/sbin/lsof -u $_ | /usr/bin/wc -l`;
$n =~ s/\s+//g;
$sum += $n;
"$_ = $n"
} #opt_u ), "; total files: $sum\n";
print "Number of open files for users:" ;
for my $opt_u (#opt_u){
my $generic_acc_open = `/usr/sbin/lsof -u $opt_u | /usr/bin/wc -l`;
chomp ($generic_acc_open);
print " $opt_u=$generic_acc_open";
}
print "\n";

Can I pipe a webpage's source from curl to perl?

I'm parsing the sourcecode of many websites, an entire huge web with thousands of pages. Now I want to search for stuff in perĺ, I want to find the number of occurrences of a keyword.
For parsing the webpages I use curl and pipe the output to "grep -c" which doesn't work, so I want to use perl. Can be perl utilised completely to crawl a page?
E.g.
cat RawJSpiderOutput.txt | grep parsed | awk -F " " '{print $2}' | xargs -I replaceStr curl replaceStr?myPara=en | perl -lne '$c++while/myKeywordToSearchFor/g;END{print$c}'
Explanation: In the textfile above I have usable and unusable URLs. With "Grep parsed" I fetch the usable URLs. With awk I select the 2nd column with contains the pure usable URL. So far so good. Now to this question: With Curl I fetch the source (appending some parameter, too) and pipe the whole source code of each page to perl in order to count "myKeywordToSearchFor" occurrences. I would love to do this in perl only if it is possible.
Thanks!
This uses Perl only (untested):
use strict;
use warnings;
use File::Fetch;
my $count;
open my $SPIDER, '<', 'RawJSpiderOutput.txt' or die $!;
while (<$SPIDER>) {
chomp;
if (/parsed/) {
my $url = (split)[1];
$url .= '?myPara=en';
my $ff = File::Fetch->new(uri => $url);
$ff->fetch or die $ff->error;
my $fetched = $ff->output_file;
open my $FETCHED, '<', $fetched or die $!;
while (<$FETCHED>) {
$count++ if /myKeyword/;
}
unlink $fetched;
}
}
print "$count\n";
Try something more like,
perl -e 'while(<>){my #words = split ' ';for my $word(#words){if(/myKeyword/){++$c}}} print "$c\n"'
i.e.
while (<>) # as long as we're getting input (into “$_”)
{ my #words = split ' '; # split $_ (implicit) into whitespace, so we examine each word
for my $word (#words) # (and don't miss two keywords on one line)
{ if (/myKeyword/) # whenever it's found,
{ ++$c } } } # increment the counter (auto-vivified)
print "$c\n" # and after end of file is reached, print the counter
or, spelled out strict-like
use strict;
my $count = 0;
while (my $line = <STDIN>) # except that <> is actually more magical than this
{ my #words = split ' ' => $line;
for my $word (#words)
{ ++$count; } } }
print "$count\n";

How to Convert While/Case statements in bash to perl

Here is the loop in bash:
while [ $# -ge 1 ]; do
case $1 in
-a)
shift
NUM_AGENTS=$1
;;
-h)
shift
HOST_NAME=$1
;;
-t)
shift
TIME_STAGGER=$1
;;
-un)
shift
USER_NAME=$1
;;
-pw)
shift
USER_PASS=$1
;;
-p)
shift
TARGET_PAGE=$1
;;
-s)
shift
COMMON_SID=$1
;;
esac
shift
done
How can i convert this in perl so that the argument would populate the values in the command line
php loadAgent_curl.php $NUM_AGENTS $HOST_NAME $procStartTime $i $TARGET_PAGE $reqlogfile $resplogfile $USER_NAME $USER_PASS $execDelay $COMMON_SID &
------- appended to question:
this certainly helps, and i really appreciate it, is there any way to access these parameters outside the getOptions ? here is rest of the bash script: my $i="0";
my $startTime=date +%s;
startTime=$[$startTime+$NUM_AGENTS+10]
my $PWD=pwd;
my $logdir="\$PWD/load-logs";
system(mkdir $logdir/$startTime);
my $reqlogfile="$logdir/$startTime/req.log";
my $resplogfile="$logdir/$startTime/resp.log";
print "\n";
print "##################\n";
print "LAUNCHING REQUESTS\n";
print " HOST NAME : \$HOST_NAME\n ";
print " TARGET PAGE : \$TARGET_PAGE\n ";
print " # AGENTS : \$NUM_AGENTS\n ";
print " EXECUTION TIME : \$startTime (with random stagger between 0 and \$TIME_STAGGER seconds)\n ";
print " REQ LOG FILE : $reqlogfile\n ";
print " RESP LOG FILE : $resplogfile\n ";
print "##################\n";
print "\n";
#
#
highestStart=$startTime
$startTime += $ARGV[0] + 5;
my $dTime = localtime( $startTime );
print "\n##################\nLAUNCHING REQUESTS\n
COUNT: $ARGV[0]\n
DELAY: | 1 \n
The scripts will fire at : $dTime\n##################\n\n";
while ( $ARGV[0] > $i )
{
$i++;
system("php avtestTimed.php $ARGV[0] $ARGV[2] $startTime");
print "RUN system('php avtestTimed.php $ARGV[0] $ARGV[2] $startTime'); \n";
sleep 1;
}
#
#
while [ $NUM_AGENTS -gt "$i" ]
do
i=$[$i+1]
execDelay=$((RANDOM % $TIME_STAGGER))"."$((RANDOM % 100))
procStartTime=$[$startTime]
procStartTime=$[$startTime+$execDelay]
if [ $procStartTime -gt $highestStart ]
then
highestStart=$procStartTime
fi
echo "STATUS: Queueing request $i with a delay of $execDelay seconds"
echo " '--> COMMAND: php loadAgent_curl.php $NUM_AGENTS $HOST_NAME $procStartTime $i $TARGET_PAGE $reqlogfile $resplogfile $USER_NAME $USER_PASS $execDelay $COMMON_SID"
php loadAgent_curl.php $NUM_AGENTS $HOST_NAME $procStartTime $i $TARGET_PAGE $reqlogfile $resplogfile $USER_NAME $USER_PASS $execDelay $COMMON_SID &
sleep 1
done
echo "STATUS: Waiting for queued requests to be ready"
while [ date +%s -lt $startTime ]
do
sleep 1
done
#
echo "STATUS: Waiting for last request to issue"
while [ date +%s -lt $highestStart ]
do
sleep 1
done
#
echo "STATUS: Last response issued"
#
echo "STATUS: Waiting for response log file to be created"
while [ ! -e "$resplogfile" ]
do
sleep 1
done
#
while [ wc -l "$resplogfile"| awk '{print $1'} -lt $NUM_AGENTS ]
do
#echo "(wc -l "$resplogfile"| awk '{print $1'} of $NUM_AGENTS responses recorded)"
sleep 1
done
echo "STATUS: FINISHED"
while true; do
read -p "Do you wish to view the request log? [y/n]" yn
case $yn in
[Yy]* ) cat $reqlogfile; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
while true; do
read -p "Do you wish to view the response log? [y/n]" yn
case $yn in
[Yy]* ) cat $resplogfile; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes or no.";;
esac
done
Getopt::Long library is a standard Perl way to process command line options.
Something like this will work. Not tested - caveat emptor!
Please note that since your PHP parameters are a mix between command line options AND some unidentified variables, I have designed the first example so that ALL the possible options should be stored in %args hash (e.g. your program should use $args{procStartTime} instead of $procStartTime). This allowed me to make it very short and generic.
If this is hard to read/understand, I also have a second example that's more straightforward but less generic
use Getopt::Long;
my #php_arg_order = qw(a h procStartTime i p reqlogfile
resplogfile un pw execDelay s);
my %args = map {$_ => ""} #php_arg_order;
$args{procStartTime} = "something";
$args{reqlogfile} = "a.log";
# More defaults for variables NOT passed in via command line.
# Populate them all in %args as above.
# Now load actual command line parameters.
GetOptions(\%args, map { "$_=s" } #php_arg_order) or die "Unknown parameter!\n";
system(join(" ",
"php", "loadAgent_curl.php",map { $args{$_} } #php_arg_order}, "&"));
A second, less advanced but more direct option is:
use Getopt::Long;
my %args = ();
# Now load actual command line parameters.
GetOptions(\%args,
"NUM_AGENTS|a=s"
,"HOST_NAME|h=s"
,"USER_NAME|un=s"
# ... the rest of options
# The "XXX|x" notaion allows using alias "-x" parameter
# but stores in $args{XXX} instead for better readability
) or die "Unknown parameter!\n";
system("php loadAgent_curl.php $args{NUM_AGENTS} $args{HOST_NAME} $procStartTime $i $args{TARGET_PAGE} $reqlogfile $resplogfile $args{USER_NAME} $args{USER_PASS} $execDelay $args{COMMON_SID} &");