Filehandle Quirk Perl - perl

In the following code if there is space between FILE and ( in the printf statement
like
printf FILE ("Test string inline\n");
Perl will treat FILE as a filehandle otherwise
printf FILE("Test string inline\n");
will be treated as subroutine call(If no subroutine is defined by FILE perl will through an error Undefined subroutine &main::FILE called at ./test.pl line xx ). Isn't there a better way Perl can implement this ? (Maybe this is why bareword filehandles are considered outdated ?)
#!/usr/bin/perl
use warnings;
open(FILE,">test.txt");
printf FILE ("Test string inline\n");
close(FILE);
sub FILE
{
return("Test string subroutine\n");
}

Are you asking how to avoid that error accidentally? You could wrap the handle in curlies
printf({ HANDLE } $pattern, #args);
print({ HANDLE } #args);
say({ HANDLE } #args);
Or since parens are often omitted for say, print and printf,
printf { HANDLE } $pattern, #args;
print { HANDLE } #args;
say { HANDLE } #args;
Or you could use a method call
HANDLE->printf($pattern, #args);
HANDLE->print(#args);
HANDLE->say(#args);

Try:
#!/usr/bin/env perl
use strict;
use warnings;
# --------------------------------------
use charnames qw( :full :short );
use English qw( -no_match_vars ) ; # Avoids regex performance penalty
my $test_file = 'test.txt';
open my $test_fh, '>', $test_file or die "could not open $test_file: $OS_ERROR\n";
printf {$test_fh} "Test string inline" or die "could not print $test_file: $OS_ERROR\n";
close $test_fh or die "could not close $test_file: $OS_ERROR\n";

Related

Error:Wide character in print at X at line 35, <$fh> ?(read text files from command line)

i am newbie to perl. and this is my second assignment i should create program to parse n files and print m sentences using n-grams model. long story short, i wrote this script that will take n arguments, where the first and second arguments are numeric but the rest are files names, however i am getting this error Wide character in print at ngram.pl line 35, line 1.
steps to reproduce it :
input from command line : perl ngram.pl 5 10 tale-cities.txt bleak-house.txt papers.txt
output : Wide character in print at ngram.pl line 35, line 1.
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
use Scalar::Util qw(looks_like_number);
use utf8;
use Encode;
#Charles Dickens
sub checkIfNumberic
{
my ($inp)=#_;
if (looks_like_number($inp)){
return "True";
}
else{
return "False" ;
}
}
sub main
{
my $correctInput=", your input must be something like this 5 10 somefile.txt somefile2.txt ";
my #inputs= #ARGV;
if (checkIfNumberic($inputs[0]) eq "False"){
die "first argument must be numberic $correctInput\n";
}
if (checkIfNumberic($inputs[1]) eq "False"){
die "second argument must be numberic $correctInput\n";
}
for (my $i=2; $i< scalar #inputs ;$i++)
{
if (open(my $fh, '<:encoding(UTF-8)', $inputs[$i])) {
while (my $line = <$fh>) {
chomp $line;
print "$line \n";
}
}
}
}
main();
You decoded your inputs (the script, with use utf8;; and the file, with :encoding(UTF-8)), but you didn't encode your outputs. Add
use open ':std', ':encoding(UTF-8)';
This is equivalent to
BEGIN {
binmode STDIN, ':encoding(UTF-8)';
binmode STDOUT, ':encoding(UTF-8)';
binmode STDERR, ':encoding(UTF-8)';
}
It also sets the default encoding for file handles opened in its lexical scope, you can remove the existing :encoding(UTF-8) if you want.

Trouble with IPC::Open3

I am writing a simple script using IPC::Open3. The script produces no output to either stdout or stderr, while I would expect output to both.
The complete source code:
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use IPC::Open3;
pipe my $input, my $output or die $!;
my $pid = open3(\*STDIN, $output, \*STDERR, 'dd', 'if=/usr/include/unistd.h') or die $!;
while(<$input>) {
print $_."\n";
}
waitpid $pid, 0;
I am fairly certain that I am using IPC::Open3 incorrectly. However, I am still confused as to what I should be doing.
It's the pipe. Without knowing why it's there I can't say more. This works fine.
my $reader;
my $pid = open3(\*STDIN, $reader, \*STDERR, 'dd', 'if=/usr/include/unistd.h') or die $!;
while(<$reader>) {
print $_."\n";
}
waitpid $pid, 0;
I realize it's probably just an example, but in case it's not... this is complete overkill for what you're doing. You can accomplish that with backticks.
print `dd if=/usr/include/unistd.h`
IPC::Open3 is a bit overcomplicated. There are better modules such as IPC::Run and IPC::Run3.
use strict;
use warnings;
use IPC::Run3;
run3(['perl', '-e', 'warn "Warning!"; print "Normal\n";'],
\*STDIN, \*STDOUT, \*STDERR
);
Your program suffers from the following problems:
\*STDIN (open STDIN as a pipe tied to the child's STDIN) should be <&STDIN (use the parent's STDIN as the child's STDIN).
\*STDERR (open STDERR as a pipe tied to the child's STDERR) should be >&STDERR (use the parent's STDERR as the child's STDERR).
The value you place in $output is being ignored and overwritten. Fortunately, it's being overwritten with a correct value!
You use print $_."\n";, but $_ is already newline-terminated. Either chomp first, or don't add a newline.
open3 isn't a system call, so it doesn't set $!.
open3 doesn't return false on error; it throws an exception.
So we get something like:
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw( say );
use IPC::Open3;
my $pid = open3('<&STDIN', my $output, '>&STDERR',
'dd', 'if=/usr/include/unistd.h');
while (<$output>) {
chomp;
say "<$_>";
}
waitpid($pid, 0);

PERL: repeated lines

I'm writing a perl code that print a massage/send a mail if there is a repeated line found in a file.
My code so far:
#!/usr/bin/perl
use strict;
my %prv_line;
open(FILE, "somefile") || die "$!";
while(<FILE>){
if($prv_line{$_}){
$prv_line{$_}++;
}
#my problem: print I saw this line X times
}
close FILE
My problem: How do generate a static msg with output: print "I saw this line X times" without printing the script output
Thanks
probably, here's what you want:
#!/usr/bin/perl
use strict;
use warnings;
my %lines;
while(<DATA>) {
chomp;
$lines{$_}++;
}
while (my($key, $value) = each %lines) {
print "I saw the line '$key' $value times\n";
}
__DATA__
abc
def
def
def
abc
blabla
avaddv
bla
abc
Of course, it can be improved.
Your original code is very close. Well done for use strict and putting $! in the die string. You should also always use warnings, use the three-parameter form of open, and use lexical file handles.
This program should help you.
use strict;
use warnings;
my %prv_line;
open (my $FILE, '<', 'somefile') || die $!;
while (<$FILE>) {
if ( $prv_line{$_} ) {
print "I saw this line $prv_line{$_} times\n";
}
$prv_line{$_}++;
}

How do I dump a stacktrace (Carp output) to a file in Perl?

I want to dump the output of Carp to a file handle in perl, instead of to stderr.
The file handle is already open.
What is the easiest way to do this?
example:
use strict;
use warnings;
use FileHandle;
use Carp;
my $fh = new FileHandle("log", "w") || croak "could not write 'log'";
# stuff happens
print $fh carp("stack trace");
close($fh);
The example will print "1" to the log, because that is the return value of carp.
print $fh "stack trace";
print $fh Carp::longmess();

How can I fake STDIN in Perl?

I am unit testing a component that requires user input. How do I tell Test::More to use some input that I predefined so that I don't need to enter it manually?
This is what I have now:
use strict;
use warnings;
use Test::More;
use TestClass;
*STDIN = "1\n";
foreach my $file (#files)
{
#this constructor asks for user input if it cannot find the file (1 is ignore);
my $test = TestClass->new( file=> #files );
isa_ok( $test, 'TestClass');
}
done_testing;
This code does press enter but the function is retrieving 0 not 1;
If the program reads from STDIN, then just set STDIN to be the open filehandle you want it to be:
#!perl
use strict;
use warnings;
use Test::More;
*STDIN = *DATA;
my #a = <STDIN>;
is_deeply \#a, ["foo\n", "bar\n", "baz\n"], "can read from the DATA section";
my $fakefile = "1\n2\n3\n";
open my $fh, "<", \$fakefile
or die "could not open fake file: $!";
*STDIN = $fh;
my #b = <STDIN>;
is_deeply \#b, ["1\n", "2\n", "3\n"], "can read from a fake file";
done_testing;
__DATA__;
foo
bar
baz
You may want to read more about typeglobs in perldoc perldata and more about turning strings into fake files in the documentation for open (look for "Since v5.8.0, perl has built using PerlIO by default.") in perldoc perlfunc.
The following minimal script seems to work:
#!/usr/bin/perl
package TestClass;
use strict;
use warnings;
sub new {
my $class = shift;
return unless <STDIN> eq "1\n";
bless {} => $class;
}
package main;
use strict;
use warnings;
use Test::More tests => 1;
{
open my $stdin, '<', \ "1\n"
or die "Cannot open STDIN to read from string: $!";
local *STDIN = $stdin;
my $test = TestClass->new;
isa_ok( $test, 'TestClass');
}
Output:
C:\Temp> t
1..1
ok 1 - The object isa TestClass