I have below syntax used in shell script-
imp_vol -u $undr_price -s $str_price -p $price -t $mat -c $iscall | grep "Black Scholes " | cut-d"=" -f2
Where imp_vol is an executable that prints something. What will be its equivalent in Perl script? For example:
imp_vol -u 110.5 -s 110.9 -p 0.005 -t 0.041 -c 1
Underlying Price = 110.5
Strike Price = 110.9
Price = 0.005
Time = 0.041
IsCall = 1
Black Scholes Vol = 0.0108141
So my purpose is to get the value of Black Scholes Vol in this case as `.0108141 in some variable,as I have to pass that variable in some function again.
Any help will be appreciated.
There is actually a grep function in perl. It takes an expression or a block as the first argument and a list of strings as the second argument. So you could do this:
my #list = grep(/abcd/, (<>));
See also: grep - perldoc.perl.org
In your specific case you can use the block form to extract the price like this:
imp_vol | perl -e 'print grep { s/\s+Black Scholes Vol = ([-+]?[0-9]*\.?[0-9]+)/$1/ } (<>)'
If you want all "Black Scholes " like your grep would match
imp_vol -u $undr_price -s $str_price -p $price -t $mat -c $iscall | perl -ne 'print $1 if $_ =~ /Black Scholes .* = (\d+(?:\.\d+)?)/;'
"Black Scholes Vol" exactly
| perl -ne 'print $1 if $_ =~ /Black Scholes Vol = (\d+(?:\.\d+)?)/;'
Use Regexes
while (<>) {
next if !/abcd/;
# ...
}
Also, to replace cut, use capture groups, but I can't provide more code because I don"t know your data format.
To execute the command, you can use open to get a filehandle from which you can read its output. You can then use a single regular expression to match the line and extract the value. For example:
my $cmd = "imp_vol -u $undr_price -s $str_price -p $price -t $mat -c $iscall";
open (my $imp, '-|', $cmd) or die "Couldn't execute command: $!";
my $extracted;
while (<$imp>) {
if (/Black Scholes Vol = (.*)/) {
$extracted = $1;
}
}
close $imp;
The parenthesis create a capture group which extracts the value into the special $1 variable.
If you're able to pipe input instead of having to execute the command within Perl, the following one-liner would suffice:
imp_vol ... | perl -ne 'print $1 if /Black Scholes Vol = (.*)/'
Related
In the below script. am not able to change the directory.i need the output like above 70% disk inside that directory which one is consuming more space.
#!/usr/bin/perl
use strict;
use warnings;
my $test=qx("df -h |awk \+\$5>=70 {print \$6} ");
chdir($test) or die "$!";
print $test;
system("du -sh * | grep 'G'");
No need to call awk in your case because Perl is quite good at splitting and printing certain lines itself. Your code has some issues:
The code qx("df -h |awk \+\$5>=70 {print \$6} ") tries to execute the string "df -h | awk ..." as a command which fails because there is no such command called "df -h | awk". When I run that code I get sh: 1: df -h |awk +>=70 {print } : not found. You can fix that by dropping the quotes " because qx() already is quoting. The variable $test is empty afterwards, so the chdir changes to your $HOME directory.
Then you'll see the next error: awk: line 1: syntax error at or near end of line, because it calls awk +\$5>=70 {print \$6}. Correct would be awk '+\$5>=70 {print \$6}', i.e. with ticks ' around the awk scriptlet.
As stated in a comment, df -h splits long lines into two lines. Example:
Filesystem 1K-blocks Used Available Use% Mounted on
/long/and/possibly/remote/file/system
10735331328 10597534720 137796608 99% /local/directory
Use df -hP to get guaranteed column order and one line output.
The last system call shows the directory usage (space) for all lines containing the letter G. I reckon that's not exactly what you want.
I suggest the following Perl script:
#!/usr/bin/env perl
use strict;
use warnings;
foreach my $line ( qx(df -hP) ) {
my ($fs, $size, $used, $avail, $use, $target) = split(/\s+/, $line);
next unless ($use =~ /^\d+\s*\%$/); # skip header line
# now $use is e.g. '90%' and we drop the '%' sign:
$use =~ s/\%$//;
if ($use > 70) {
print "almost full: $target; top 5 directories:\n";
# no need to chdir here. Simply use $target/* as search pattern,
# reverse-sort by "human readable" numbers, and show the top 5:
system("du -hs $target/* 2>/dev/null | sort -hr | head -5");
print "\n\n";
}
}
#!/usr/bin/perl
use strict;
use warnings;
my #bigd = map { my #f = split " "; $f[5] }
grep { my #f = split " "; $f[4] =~ /^(\d+)/ && $1 >= 70}
split "\n", `df -hP`;
print "big directories: $_\n" for #bigd;
for my $bigd (#bigd) {
chdir($bigd);
my #bigsubd = grep { my #f = split " "; $f[0] =~ /G/ }
split "\n", `du -sh *`;
print "big subdirectories in $bigd:\n";
print "$_\n" for #bigsubd;
}
I belive you wanted to do something like this.
I have a tab delimited file(dummy) that looks like this :
a b
a b
a c
a c
a b
I am trying to write an awk command inside the perl script in which the file.txt is being made.
The awk command :
$n=system(" awk -F"\t" '{if($1=="a" && $2=="b") print $1,$2}' file.txt|wc -l ")
Error :
comparison operator :error in '==' , ',' between $1 and $2 in print }'
The awk script is running fine on command line but giving error while running inside the script.
I don't see any syntax error in the awk command.
Aside from the fact that what are you trying to achieve by executing awk from within perl (since it could be accomplished using the latter itself), you could use the q operator:
$cmd = q(awk -F"\t" '{if($1=="a" && $2=="b") print $1,$2}' file.txt | wc -l);
$n = system($cmd);
Note that using double-quotes would interpolate variables and you'd need to escape those.
You can get the number of a\tbs from Perl itself without calling an external command:
#!/usr/bin/perl
use warnings;
use strict;
open my $FH, '<', 'file.txt' or die $!;
my $n = 0;
"a\tb\n" eq $_ and $n++ while <$FH>;
print "$n\n";
How to add a blank line after every grep result?
For example, grep -o "xyz" may give something like -
file1:xyz
file2:xyz
file2:xyz2
file3:xyz
I want the output to be like this -
file1:xyz
file2:xyz
file2:xyz2
file3:xyz
I would like to do something like
grep "xyz" | perl (code to add a new line after every grep result)
This is the direct answer to your question:
grep 'xyz' | perl -pe 's/$/\n/'
But this is better:
perl -ne 'print "$_\n" if /xyz/'
EDIT
Ok, after your edit, you want (almost) this:
grep 'xyz' * | perl -pe 'print "\n" if /^([^:]+):/ && ! $seen{$1}++'
If you don’t like the blank line at the beginning, make it:
grep 'xyz' * | perl -pe 'print "\n" if /^([^:]+):/ && ! $seen{$1}++ && $. > 1'
NOTE: This won’t work right on filenames with colons in them. :)½
If you want to use perl, you could do something like
grep "xyz" | perl -p -e 's/(.*)/\1\n/g'
If you want to use sed (where I seem to have gotten better results), you could do something like
grep "xyz" | sed 's/.*/\0\n/g'
This prints a newline after every single line of grep output:
grep "xyz" | perl -pe 'print "\n"'
This prints a newline in between results from different files. (Answering the question as I read it.)
grep 'xyx' * | perl -pe '/(.*?):/; if ($f ne $1) {print "\n"; $f=$1}'
Use a state machine to determine when to print a blank line:
#!/usr/bin/env perl
use strict;
use warnings;
# state variable to determine when to print a blank line
my $prev_file = '';
# change DATA to the appropriate input file handle
while( my $line = <DATA> ){
# did the state change?
if( my ( $file ) = $line =~ m{ \A ([^:]*) \: .*? xyz }msx ){
# blank lines between states
print "\n" if $file ne $prev_file && length $prev_file;
# set the new state
$prev_file = $file;
}
# print every line
print $line;
}
__DATA__
file1:xyz
file2:xyz
file2:xyz2
file3:xyz
How can I write a Perl script to convert a text file to all upper case letters?
perl -ne "print uc" < input.txt
The -n wraps your command line script (which is supplied by -e) in a while loop. A uc returns the ALL-UPPERCASE version of the default variable $_, and what print does, well, you know it yourself. ;-)
The -p is just like -n, but it does a print in addition. Again, acting on the default variable $_.
To store that in a script file:
#!perl -n
print uc;
Call it like this:
perl uc.pl < in.txt > out.txt
$ perl -pe '$_= uc($_)' input.txt > output.txt
perl -pe '$_ = uc($_)' input.txt > output.txt
But then you don't even need Perl if you're using Linux (or *nix). Some other ways are:
awk:
awk '{ print toupper($0) }' input.txt >output.txt
tr:
tr '[:lower:]' '[:upper:]' < input.txt > output.txt
$ perl -Tpe " $_ = uc; " --
$ perl -MO=Deparse -Tpe " $_ = uc; " -- a s d f
LINE: while (defined($_ = <ARGV>)) {
$_ = uc $_;
}
continue {
die "-p destination: $!\n" unless print $_;
}
-e syntax OK
$ cat myprogram.pl
#!/usr/bin/perl -T --
LINE: while (defined($_ = <ARGV>)) {
$_ = uc $_;
}
continue {
die "-p destination: $!\n" unless print $_;
}
cat $INPUT_FILE| while read LINE
do
abc=cut -d ',' -f 4 $LINE
Perl:
cat $INPUT_FILE | perl -ne '{my #fields = split /,/; print $fields[3];}'
The key is to use command substitution if you want the output of a command saved in a variable.
POSIX shell (sh):
while read -r LINE
do
abc=$(cut -d ',' -f 4 "$LINE")
done < "$INPUT_FILE"
If you're using a legacy Bourne shell, use backticks instead of the preferred $():
abc=`cut -d ',' -f 4 "$LINE"`
In some shells, you may not need to use an external utility.
Bash, ksh, zsh:
while read -r LINE
do
IFS=, read -r f1 f2 f3 abc remainder <<< "$LINE"
done < "$INPUT_FILE"
or
while read -r LINE
do
IFS=, read -r -a array <<< "$LINE"
abc=${array[3]}
done < "$INPUT_FILE"
or
saveIFS=$IFS
while read -r LINE
do
IFS=,
array=($LINE)
IFS=$saveIFS
abc=${array[3]}
done < "$INPUT_FILE"
Bash:
while read line ; do
cut -d, -f4 <<<"$line"
done < $INPUT_FILE
Straight Perl:
open (INPUT_FILE, "<$INPUT_FILE") or die ("Could not open $INPUT_FILE");
while (<INPUT_FILE>) {
#fields = split(/,/, $_);
$use_this_field_value = $fields[3];
# do something with field value here
}
close (INPUT_FILE);