df output issues - perl

$df_ret = `ssh -q rajesh 'df -hP'`;
print "The value is $df_ret";
if ($df_ret =~ /\/boot/)
{
print "The value is $df_ret";
}
Expected result:
/dev/sda1 126931 39530 80848 33% /boot
But, it's coming whole df -k output. Any idea?

Your regex is matching against the whole output as one string. You probably want to split it into lines, first and then match each line:
my #df_ret = `ssh -q rajesh 'df -hP'`;
foreach my $line (#df_ret) {
if ($line =~ m! /boot$!)
{
print "The value is $line";
}
}

Just using the shell:
ssh -q rajesh 'df -hP' | grep /boot

Related

awk output to variable and change directory

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.

Perl perform a pgrep with count line

I've got a problem using pgrep with the wc command. I find 2 lines where I only expect 1 line.
my $test = `pgrep -f 'blabla'`;
print $test; <------ print the good PID (only one)
my $test = `pgrep -f 'blabla'|/usr/bin/wc -l`;
print $test; <------- print 2 and a carriage return
I find that a carriage return is inserted before the pipe, so wc counts 2 lines.
Is there a way to do a intermediate chomp() beetween the pipe ?
Thank you for your help
pgrep is matching itself when you use a pipe. This can be verified if you pipe into cat instead of wc. You can avoid this by adding in some braces like so, so that the pattern no longer matches itself.
my $test = `pgrep -f '[b]labla' | /usr/bin/wc -l`;

df output in tabular form using perl

Given the following command and its output:
ssh -q $server 'df -hP /raj*
Size Used Avail Capacity Mounted On
200G 154G 44G 79% /raj_day
200G 154G 44G 49% /raj1_day
200G 154G 44G 39% /raj2_day
I would like to convert into Tabular format so presentation should be good. Also, want to display Capacity in sorting order. Any tips for me in perl?
My Script as follows...
#############################################
#!/usr/local/bin/perl
# Use either -h or -k flag or leave it blank for default (-k)
# -h for human-readable size output
# -k for 1k-block output
$flag = "-h";
#df = `df $flag`;
print "Content-type: text/htmln\n";
print "<table border=2>\n";
print "<tr>\n";
print "<td><b>Filesystem</b></td>\n";
if ($flag eq "-h") {
print "<td><b>Size</b></td>\n";
}
else {
print "<td><b>1k-blocks</b></td>\n";
}
print "<td><b>Used</b></td>\n";
print "<td><b>Avail</b></td>\n";
print "<td><b>Capacity</b></td>\n";
print "<td><b>Mounted on</b></td>\n";
print "</tr>\n";
foreach $line (#df) {
next if ($line =~ /Filesystem/);
($fsystem,$blocks,$used,$avail,$capacity,$mounted) = split(/s+/,$line);
print "fsystem is $fsystem\n";
print "blocks is $blocks\n";
print "used is $used\n";
print "avail is $avail\n";
print "capacity is $capacity\n";
print "mounted is $mounted\n";
($number,$sign) = split(/%/,$capacity);
if ($number < 60) {
print "<tr bgcolor=green>\n";
}
elsif (($number >= 60) && ($number < 90)) {
print "<tr bgcolor=yellow>\n";
}
else {
print "<tr bgcolor=red>\n";
}
#
print "<td>$fsystem</td>\n";
print "<td>$blocks</td>\n";
print "<td>$used</td>\n";
print "<td>$avail</td>\n";
print "<td>$capacity</td>\n";
print "<td>$mounted</td>\n";
print "</tr>\n";
}
print "</table>\n";
OUTPUT AS FOLLOWS
Content-type: text/htmln
Filesystem Size Used
Avail Capacity Mounted
on fsystem is /dev/ blocks is da3 95G
33G 58G 36% /
used is avail is capacity is mounted is fsystem is tmpf blocks is
499M 88K 499M 1% /dev/ used is hm
avail is capacity is mounted is fsystem is /dev/ blocks is da1
124M 39M 79M 33% /boot
used is avail is capacity is mounted is
Like daxim already pointed out: It's a stupid idea to parse the output of df, but if I had to hack down a small script it would probably look like this:
df -B M -P /path1 /path2 /path3 | sed -e '1d' | sort -k 4,4 -r -h | column -t

How to remove duplicate line by perl or bash?

I have a list:
asd#domain.com
fff#domain.com
yyy#domain.com
ttt#test.com
rrr#test.com
fff#test.com
yyy#my.com
yyy#my.com
How it possible to do this:
if in whole list we see three or more email with same domain - all duplicates except first one need to remove.
Output:
asd#domain.com
ttt#test.com
yyy#my.com
yyy#my.com
#!/usr/bin/env perl
use strict; use warnings;
use Email::Address;
my %data;
while (my $line = <DATA>) {
my ($addr) = Email::Address->parse($line =~ /^(\S+)/);
push #{ $data{ $addr->host } }, $addr->original;
}
for my $addrs (values %data) {
if (#$addrs > 2) {
print "$addrs->[0]\n";
}
else {
print "$_\n" for #$addrs;
}
}
__DATA__
asd#domain.com
fff#domain.com
yyy#domain.com
ttt#test.com
rrr#test.com
fff#test.com
yyy#my.com
yyy#my.com
sed -s 's/#/#\t/g' test.txt | uniq -f 1 | sed -s 's/#\t/#/g'
The first sed separates the email in 2 fields (name + domain) with a tab character, so that uniq can skip the first field when removing the duplicate domains, and the last sed removes the tab.
I am puzzled why your example output contains yyy#my.com twice but assume it is a mistake.
As long as there are no issues with trailing space characters or more complex forms of email addresses you can do this simply in Perl with
perl -aF# -ne 'print unless $seen{$F[1]}++' myfile
output
asd#domain.com
ttt#test.com
yyy#my.com
This might work for you:
sed ':a;$!N;s/^\([^#]*#\([^\n]*\)\)\n.*\2/\1/;ta;P;D' file
asd#domain.com
ttt#test.com
yyy#my.com
If you don't mind the order, just use sort:
sort -t '#' -u -k 2,2 your_file
If you do mind the order, do
gawk '{print NR "#" $0}' your_file | sort -t '#' -u -k 3,3 | sort -t '#' -k 1,1n | cut -d \# -f 2-

How do I search text then print the result?

I am searching for "o" then prints all lines with "o". Any suggestion/code I must apply?
data.txt:
j,o,b:
a,b,d:
o,l,e:
f,a,r:
e,x,o:
desired output:
j,o,b:
o,l,e:
e,x,o:
grep o data.txt
perl -ne 'print if (/o/);' <data.txt
If you have grep on your system, then grep o data.txt from the command line should do the trick.
Failing that, you could try Perl:
open IN, 'data.txt';
my #l = <IN>;
close IN;
foreach my $l (#l) {
$l =~ /o/ and print $l;
}
grep "o" data.txt
Does that help? I don't know Perl, but you can get the same output using the above grep.
print if /o/;
In Perl:
while (<>) { print if /o/; }
or with grep:
grep 'o' data.txt
as a very short one-liner:
> perl -pe'$_ x=/o/' filename