Using AWK in a Perl script? - perl

This is what I'm trying to do:
$variable = `grep -i "Text: Added to directory" '$FOO/result.txt' | awk '{print $6}' | tr -d "'"`
print $variable;
Output:
Text: Added to directory /path/to/directory/
Use of uninitialized value $6 in concatenation (.) or string
How can I fetch just "/path/to/directory" instead of "Text: Added to directory /path/to/directory/"?

Of course Perl can do what grep, awk and tr can do.
open my $fh, "<", "$FOO/result.txt" or die "can't open file: $!\n";
while (<$fh>) {
next unless /pattern/i;
(my $six = (split)[5]) =~ tr/'//d;
print $six, "\n";
}
close $fh;

You probably need to adjust the quote-escaping but this should do:
awk IGNORECASE=1 '/yourpattern/{ gsub(/\'/, \'\'); print $6 }' $FOO/result.txt
AWK is pretty versatile.

Related

how to awk values of perl array?

I have an some attributes with values stored in an array as below, now i need to perform some checks on attribute values,Suggest me how can i proceed in perl.
#arr1 = `cat passwd.txt|tr ' ' '\n'|egrep -i "maxage|minage"|sort'`;
array arr1 contains info as "maxage=0 minage=0"
In this i need to perform if condition on the value of maxage, is there any way like below, suggest me as i am new to perl.
if ( #arr1[0]|awk -F= '{print $2}' == 0 )
{
printf "Then print task done";
}
You can do the whole process in Perl. For example:
use feature qw(say);
use strict;
use warnings;
my $fn = 'passwd.txt';
open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
my #arr1 = sort grep /maxage|minage/i, split ' ', <$fh>;
close $fh;
if ( (split /=/, shift #arr1)[1] == 0) {
say "done";
}
Can you try this?
#arr1 = `cat passwd.txt | tr ' ' '\n' | grep -i "maxage|minage"| sort`;
$x = `$arr1[0] | awk -F= {print $2}`; // maybe $3 is true index
if ( x == 0 )
{
print "Then print task done";
}

copy everything before the first blank line

I have a file with several blocks of text separated by blank line. Ex.:
block1
block1
block2
block3
block3
I need a solution with sed, awk or Perl to locate the first blank line and redirect the previous block to another file and so on until the end of the file.
I have this command in sed that locates the first block, but not the rest:
sed -e '/./!Q'
Can someone help me?
give this line a try:
awk -v RS="" '{print > "file"++c".txt"}' input
it will generate file1...n.txt
Here's an awk:
$ awk 'BEGIN{file="file"++cont}/^$/{file="file"++cont;next}{print>file}' infile
Results
$ cat file1
block1
block1
$ cat file2
block2
$ cat file3
block3
block3
taking into account several empty string between block
awk '/./{if(!L)++C;print>"Out"C".txt"}{L=$0!~/^$/}' YourFile
Sed will not allow different external files (unspecified number of in fact) as output
Here's the solution in Perl
open( my $fh, '<', '/tmp/a.txt' ) or die $!;
{
## record delimiter
local $/ = "\n\n";
my $count = 1;
while ( chomp( my $block = <$fh> ) ) {
open( my $ofh, '>', sprintf( '/tmp/file%d', $count++ ) ) or die $!;
print {$ofh} $block;
close($ofh);
}
}
close($fh);
Here's my solution in Perl:
#!/usr/bin/perl
use strict;
use warnings;
my $n = 0;
my $block = '';
while (<DATA>) { # line gets stored in $_
if (/^\s*$/) { # blank line
write_to_file( 'file' . ++$n, $block );
$block = '';
} else {
$block .= $_;
}
}
# Write any remaining lines
write_to_file( 'file' . ++$n, $block );
sub write_to_file {
my $file = shift;
my $data = shift;
open my $fh, '>', $file or die $!;
print $fh $data;
close $fh;
}
__DATA__
block1
block1
block2
block3
block3
Output:
$ grep . file*
file1:block1
file1:block1
file2:block2
file3:block3
file3:block3
Another way to do it in Perl:
#!/usr/bin/perl
use strict;
use warnings;
# store all lines in $data
my $data = do { local $/; <DATA> };
my #blocks = split /\n\n/, $data;
my $n = 0;
write_to_file( 'file' . ++$n, $_ ) for #blocks;
sub write_to_file {
my $file = shift;
my $data = shift;
open my $fh, '>', $file or die $!;
print $fh $data;
close $fh;
}
__DATA__
block1
block1
block2
block3
block3
This might work for you (GNU csplit & sed):
csplit -qf uniqueFileName file '/^$/' '{*}' && sed -i '/^$/d' uniqueFileName*
or if you want to go with the defaults:
csplit -q file '/^$/' '{*}' && sed -i '/^$/d' xx*
Use:
tail -n+1 xx* # to check the results

How to call shell from perl script

Perl script reads url from config file. In config file data stored as URL=http://example.com.
How can I get site name only. I've tried
open(my $fh, "cut -d= -f2 'webreader.conf'");
But it doesn't work.
Please, help!
You have to indicate with reading pipe -| that what follows is command which gets forked,
open(my $fh, "-|", "cut -d= -f2 'webreader.conf'") or die $!;
print <$fh>; # print output from command
Better approach would be to read file directly by perl,
open( my $fh, "<", "webreader.conf" ) or die $!;
while (<$fh>) {
chomp;
my #F = split /=/;
print #F > 1 ? "$F[1]\n" : "$_\n";
}
Maybe something like this?
$ cat urls.txt
URL=http://example.com
URL=http://example2.com
URL=http://exampleXXX.com
$ ./urls.pl
http://example.com
http://example2.com
http://exampleXXX.com
$ cat urls.pl
#!/usr/bin/perl
$file='urls.txt';
open(X, $file) or die("Could not open file.");
while (<X>) {
chomp;
s/URL=//g;
print "$_\n";
}
close (X);

Grep to match all lines of patternfile (perl -e ok too)

I'm looking for a simple/elegant way to grep a file such that every returned line must match every line of a pattern file.
With input file
acb
bc
ca
bac
And pattern file
a
b
c
The command should return
acb
bac
I tried to do this with grep -f but that returns if it matches a single pattern in the file (and not all). I also tried something with a recursive call to perl -ne (foreach line of the pattern file, call perl -ne on the search file and try to grep in place) but I couldn't get the syntax parser to accept a call to perl from perl, so not sure if that's possible.
I thought there's probably a more elegant way to do this, so I thought I'd check. Thanks!
===UPDATE===
Thanks for your answers so far, sorry if I wasn't clear but I was hoping for just a one-line result (creating a script for this seems too heavy, just wanted something quick). I've been thinking about it some more and I came up with this so far:
perl -n -e 'chomp($_); print " | grep $_ "' pattern | xargs echo "cat input"
which prints
cat input | grep a | grep b | grep c
This string is what I want to execute, I just need to somehow execute it now. I tried an additional pipe to eval
perl -n -e 'chomp($_); print " | grep $_ "' pattern | xargs echo "cat input" | eval
Though that gives the message:
xargs: echo: terminated by signal 13
I'm not sure what that means?
One way using perl:
Content of input:
acb
bc
ca
bac
Content of pattern:
a
b
c
Content of script.pl:
use warnings;
use strict;
## Check arguments.
die qq[Usage: perl $0 <input-file> <pattern-file>\n] unless #ARGV == 2;
## Open files.
open my $pattern_fh, qq[<], pop #ARGV or die qq[ERROR: Cannot open pattern file: $!\n];
open my $input_fh, qq[<], pop #ARGV or die qq[ERROR: Cannot open input file: $!\n];
## Variable to save the regular expression.
my $str;
## Read patterns to match, and create a regex, with each string in a positive
## look-ahead.
while ( <$pattern_fh> ) {
chomp;
$str .= qq[(?=.*$_)];
}
my $regex = qr/$str/;
## Read each line of data and test if the regex matches.
while ( <$input_fh> ) {
chomp;
printf qq[%s\n], $_ if m/$regex/o;
}
Run it like:
perl script.pl input pattern
With following output:
acb
bac
Using Perl, I suggest you read all the patterns into an array and compile them. Then you can read through your input file using grep to make sure all of the regexes match.
The code looks like this
use strict;
use warnings;
open my $ptn, '<', 'pattern.txt' or die $!;
my #patterns = map { chomp(my $re = $_); qr/$re/; } grep /\S/, <$ptn>;
open my $in, '<', 'input.txt' or die $!;
while (my $line = <$in>) {
print $line unless grep { $line !~ $_ } #patterns;
}
output
acb
bac
Another way is to read all the input lines and then start filtering by each pattern:
#!/usr/bin/perl
use strict;
use warnings;
open my $in, '<', 'input.txt' or die $!;
my #matches = <$in>;
close $in;
open my $ptn, '<', 'pattern.txt' or die $!;
for my $pattern (<$ptn>) {
chomp($pattern);
#matches = grep(/$pattern/, #matches);
}
close $ptn;
print #matches;
output
acb
bac
Not grep and not a one liner...
MFILE=file.txt
PFILE=patterns
i=0
while read line; do
let i++
pattern=$(head -$i $PFILE | tail -1)
if [[ $line =~ $pattern ]]; then
echo $line
fi
# (or use sed instead of bash regex:
# echo $line | sed -n "/$pattern/p"
done < $MFILE
A bash(Linux) based solution
#!/bin/sh
INPUTFILE=input.txt #Your input file
PATTERNFILE=patterns.txt # file with patterns
# replace new line with '|' using awk
PATTERN=`awk 'NR==1{x=$0;next}NF{x=x"|"$0}END{print x}' "$PATTERNFILE"`
PATTERNCOUNT=`wc -l <"$PATTERNFILE"`
# build regex of style :(a|b|c){3,}
PATTERN="($PATTERN){$PATTERNCOUNT,}"
egrep "${PATTERN}" "${INPUTFILE}"
Here's a grep-only solution:
#!/bin/sh
foo ()
{
FIRST=1
cat pattern.txt | while read line; do
if [ $FIRST -eq 1 ]; then
FIRST=0
echo -n "grep \"$line\""
else
echo -n "$STRING | grep \"$line\""
fi
done
}
STRING=`foo`
eval "cat input.txt | $STRING"

What's the best way to convert "awk '{print $2 >> $1}' file" in a Perl one-liner?

How could I convert:
awk '{print $2 >> $1}' file
in a short Perl one-liner?
"file" could look like this:
fruit banana
vegetable beetroot
vegetable carrot
mushroom chanterelle
fruit apple
there may some other ways, but here's what i can think of
perl -ane 'open(FILE,">>",$F[0]); print FILE $F[1];close(FILE);' file
I guess awk has to be better at some things :-)
This is right at the limit of what I'd do on the command line, but it avoids reopening filehandles.
$ perl -lane '$fh{$F[0]} || open $fh{$F[0]}, ">>", $F[0]; print {$fh{$F[0]}} $F[1]' file
Not pure Perl, but you can do:
perl -nae '`echo $F[1] >> $F[0]`' input_file
This is what a2p <<< '{print $2 >> $1}' produces
#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$#"}'
if $running_under_some_shell;
# this emulates #! processing on NIH machines.
# (remove #! line above if indigestible)
eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;
# process any FOO=bar switches
$, = ' '; # set output field separator
$\ = "\n"; # set output record separator
while (<>) {
($Fld1,$Fld2) = split(' ', $_, -1);
&Pick('>>', $Fld1) &&
(print $fh $Fld2);
}
sub Pick {
local($mode,$name,$pipe) = #_;
$fh = $name;
open($name,$mode.$name.$pipe) unless $opened{$name}++;
}