Perl: Format table with curl outputs - perl

I have something like the following curl code:
foreach my $value ('1', ..., '5') {
my $count = 1;
print "\nValue: $value\n\t";
my $start = `curl -m 10 -s "http://SITE/?value=$value" -c cookie.txt`;
my $end1 = `curl -m 10 -s "http://SITE2" -b cookie.txt`;
if($end1 ne "") {print ". "}; else print "$count ";
my $end2 = `curl -m 10 -s "http://SITE3" -b cookie.txt`;
if($end2 ne "") {print ". "}; else print "$count ";
my $end3 = `curl -m 10 -s "http://SITE4" -b cookie.txt`;
if($end3 ne "") {print ". "}; else print "$count ";
$count++;
}
So from value 1 to 5, it visits a website and stores the cookie value in cookie.txt. Then it visits 3 different websites using the stored cookies in cookie.txt. Once it visits these sites, it prints current count (or . if the request timed out after 10 seconds).
An example output for this would be:
Value: 1
1 1 1 2 . 2 3 3 3 4 . . . 5 5
Value: 2
. . 1 2 2 2 3 3 3 4 . 4 5 5 .
Would it be possible to format the output to look like:
Value: 1
Site2: 1 2 3 4 .
Site3: 1 . 3 . 5
Site4: 1 2 3 . 5
Value: 2
Site2: . 2 3 4 5
Site3: . 2 3 . 5
Site4: 1 2 3 4 .
The issue I have is that in the loop, I would only like to run $start once per loop. With the way I want it formatted, it would have to be run once per site (3 times).

Your requirement is a bit confusing, but this will give you the output you're seeking:
my #sites = qw( SITE2 SITE3 SITE4 );
foreach my $value ('1'..'5') {
print "\nValue: $value\n";
my $start = `curl -m 10 -s "http://SITE/?value=$value" -c cookie.txt`;
for my $site (#sites) {
print "\t$site ";
for (1..5) { # assuming you want to fetch each url 5x
my $end = `curl -m 10 -s "http://$site" -b cookie.txt`;
print $end eq '' ? '. ' : $_.' ';
}
print "\n";
}
}

Please turn on use strict; and use warnings.
If you did, you'd find:
foreach my $value ('1', ..., '5') {
print $value,"\n";
}
Is a syntax error. Which is not a good start. Perhaps you want:
foreach my $value ( 1..5) {
print $value,"\n";
}
Likewise you've to a $count variable that you never change, because you scope it locally within your loop (via my) and set it to 1 each iteration. And then increment it right at the end, just before it drifts out of scope.

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!

Different result in forloop?

I want to print like this
xxx
xxxxx
xxxxxxx
xxxxxxxxx
xxxxxxxxxxx
I achive this by following code
$s = "x";
$z = 5;
$m = 1;
$m = $m+2,
$z--,
$c = " " x $z,
$st = $s x $m,
print "$c$st\n",
for(1..5);
My doubt
when i used increment and decrement operator after the print function it gave the different result
Script is
$c = " " x $z,
$st = $s x $m,
print "$c$st\n",
$m = $m+2,
$z--,
for(1..5);
It result is
x
35 xxx
54 xxxxx
73 xxxxxxx
92 xxxxxxxxx
Here 3 5 7 9 are printed by the $m and 5 4 3 2 are printed by the $z.
But, i not directly print the $m and $z then why it gave $m and $z value? How it is work?
The code
$c = " " x $z,
$st = $s x $m,
print "$c$st\n",
$m = $m+2,
$z--,
for(1..5);
is parsed as:
$c = " " x $z,
$st = $s x $m,
print ("$c$st\n", $m = $m+2, $z--),
for(1..5);
You can force different parsing by using parentheses:
$c = " " x $z,
$st = $s x $m,
print ("$c$st\n"),
$m = $m+2,
$z--
for(1..5);
But I rather suggest the following:
for(1..5) {
$c = " " x $z;
$st = $s x $m;
print ("$c$st\n");
$m = $m+2;
$z--;
}
That way you are not relying on any operator precedence which might bite you. You will immediately see which statements are contained in the loop too. (I had to read your initial code thrice to finally get it)

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";

remove duplicate values for a key in hash

I have the following code
chdir("c:/perl/normalized");
$docid=0;
my %hash = ();
#files = <*>;
foreach $file (#files)
{
$docid++;
open (input, $file);
while (<input>)
{
open (output,'>>c:/perl/tokens/total');
chomp;
(#words) = split(" ");
foreach $word (#words)
{
push #{ $hash{$word} }, $docid;
}
}
}
foreach $key (sort keys %hash) {
print output"$key : #{ $hash{$key} }\n";
}
close (input);
close (output);
This is a sample output in a file
of : 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 4 4 4 4 5 6 6 7 7 7 7 7 7 7 7 7
it is true since the term "of" for example existed 10(ten ones) times in the first document
however is there a way to remove the repeated values; i.e instead of ten ones I want just one
Thank you for your help
To avoid adding the dups in the first place, change
foreach $word (#words)
to
foreach $word (uniq #words)
If you want to leave the dups in the data structure, instead change
print output"$key : #{ $hash{$key} }\n";
to
print output "$key : ", join(" ", uniq #{ $hash{$key} }), "\n";
uniq is provided by List::MoreUtils.
use List::MoreUtils qw( uniq );
Or you can use
sub uniq { my %seen; grep !$seen{$_}++, #_ }

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} &");