Difference in behaviour between Perl versions - perl

I have the following script
#!/usr/bin/perl -w
print "sample\n";
syswrite STDIN, "script";
my $input = <STDIN>;
print "$input";
This scripts executes properly in Perl 5.8.8 version giving the following output:
sample
script
However when executed in Perl 5.14.2 it gives the following error:
Filehandle STDIN opened only for input at ./sample.pl line 5.
What has been changed between the Perl versions?

Presumably, you're asking to replicate the 5.8.8 behaviour. I'm not sure how much sense makes to do so, but you can create a Perl read-write handle attached to the same file descriptor as follows:
$ perl -e'
open(my $fh, "+>&=", 0) or die $!;
print($fh "foo\n") or die $!;
' >/dev/null
foo
or
$ perl -e'
{
open(my $fh, "+>&=", 0) or die $!;
close(STDIN);
open(STDIN, "+>&=", $fh) or die $!;
}
print(STDIN "foo\n") or die $!;
' >/dev/null
foo

Related

awk usage in perl scripting

Hi am writing a script which its need to grep the 6th column of the output using awk command but am getting other output.
What is the exact syntax in perl to extract 6th column using awk?
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
my $filesystem=`df -h |grep -i dev|grep -vE '^Filesystem|proc|none|udev|tmpfs'`;
print "(\"$filesystem\"|awk '{print \$6}')"
Output :
7831c1c4be8c% ./test.pl
("/dev/disk1 112Gi 43Gi 69Gi 39% 11227595 18084674 38% /
devfs 183Ki 183Ki 0Bi 100% 634 0 100% /dev
"|awk '{print $6}')%
Am trying to remove the % how it can be done ?
7831c1c4be8c% cat test.pl
#!/usr/bin/perl
use warnings;
use strict;
open my $FS, q(df -h |) or die $!;
while (<$FS>) {
print +(split)[4], "\n"
if /dev/i and not /devfs/;
}
7831c1c4be8c% ./test.pl
40%
You don't need awk inside Perl.
#!/usr/bin/perl
use warnings;
use strict;
open my $FS, '-|', q(df -h) or die $!;
while (<$FS>) {
print +(split)[5], "\n"
if /dev/i and not /^Filesystem|proc|none|udev|tmpfs/;
}
as the previous answer says, you don't need awk or grep system calls in perl. however, I will tell you that one reason your code isn't working is because you never made the awk system call. print does not execute the system call. you would have to use system() to execute it.
anyway fwiw you can also do what you want in a one-liner like so:
df -h | perl -lnae 'next if $F[0] =~ /regex/; print $F[5]'

Running a background process in perl

I have a process which when
executed as below:
process_name > file.txt
will redirect all the output to file.txt and also to the console.
when executed like this
process_name >& file.txt&
will redirect the output to file.txt but will not print the output to console returning the pid on the console.
Now i want to execute the second way of running the process inside a perl script!
how could i do this?
currently i am usng the below method:
#!/usr/bin/perl
use strict;
use warnings;
my $res = `bsm_adjust_controller -F -ra -d 'subnetwork=NETSim_STD/bsc=0005' -f /tmp/31102012/Task_31102012_1421_0005.log >& /tmp/31102012/Ctrl_31102012_1421_0005.log&`;
print $res;
when i run the script it gives:
./temp.pl
sh: /tmp/31102012/Ctrl_31102012_1421_0005.log: bad number
I also tried the below method:
#!/usr/bin/perl
use strict;
use warnings;
my $res = "bsm_adjust_controller -F -ra -d 'subnetwork=NETSim_STD/bsc=0005' -f /tmp/31102012/Task_31102012_1421_0005.log >& /tmp/31102012/Ctrl_31102012_1421_0005.log&";
open(CMD, '-|', $res) || die "couldn't run $res: $!\n";
Even the above script throws the same error.
the purpose is to execute the process in background and continue with the next statements without caring what happened to the process and also i donot need the output of the process being run inside to console.
could anybody please help?
well this worked:
#!/usr/bin/perl
use strict;
use warnings;
my $cmd="bsm_adjust_controller -F -ra -d 'subnetwork=NETSim_STD/bsc=0106' -f /tmp/31102012/Task_31102012_1421_0005.log >/tmp/31102012/Ctrl_31102012_1421_0005.log";
open STDERR, ">/dev/null";
print "Redirected stderr to /dev/null\n";
my $pid=open (FH, "-|",$cmd);
if ($pid) { #parent
print "/tmp/31102012/Task_31102012_1421_0005.log";
exit;
}
print "Redirected stderr to /dev/null\n";
close(FH);

Perl - One liner file edit: "perl -n -i.bak -e "print unless /^$id$,/" $filetoopena;" Not working

I cannot get this to work.
#!/usr/bin/perl -w
use strict;
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
my $id='123456';
my $filetoopen = '/home/user/public/somefile.txt';
file contains:
123456
234564
364899
437373
So...
A bunch of other subs and code
if(-s $filetoopen){
perl -n -i.bak -e "print unless /^$id$,/" $filetoopen;
}
I need to remove the line that matches $id from file $filetoopen
But, I don't want script to "crash" if $id is not in $filetoopen either.
This is in a .pl scripts sub, not being run from command line.
I think I am close but, after reading for hours here, I had to resort to posting the question.
Will this even work in a script?
I tried TIE with success but, I need to know alternatively how to do this without TIE::FILE.
When I tried I got the error:
syntax error at mylearningcurve.pl line 456, near "bak -e "
Thanks for teaching this old dog...
First of all (this is not the cause of your problem) $, (aka $OUTPUT_FIELD_SEPARATOR) defaults to undef, I'm not sure why you are using it in the regex. I have a feeling the comma was a typo.
It's unclear if you are calling this from a shell script or from Perl?
If from Perl, you should not call a nested Perl interpreter at all.
If the file is small, slurp it in and print:
use File::Slurp;
my #lines = read_file($filename);
write_file($filename, grep { ! /^$id$/ } #lines);
If the file is large, read line by line as a filter.
use File::Copy;
move($filename, "$filename.old") or die "Can not rename: $!\n";
open(my $fh_old, "<", "$filename.old") or die "Can not open $filename.old: $!\n";
open(my $fh, ">", $filename) or die "Can not open $filename: $!\n";
while my $line (<$fh_old>) {
next if $line =~ /^id$/;
print $fh $_;
}
close($fh_old);
close($fh);
If from a shell script, this worked for me:
$ cat x1
123456
234564
364899
437373
$ perl -n -i.bak -e "print unless /^$id$/" x1
$ cat x1
234564
364899
437373
if(-s $filetoopen){
perl -n -i.bak -e "print unless /^$id$,/" $filetoopen;
}
I'm not at all sure what you expect this to do. You can't just put a command line program in the middle of Perl code. You need to use system to call an external program. And Perl is just an external program like any other.
if(-s $filetoopen){
system('perl', '-n -i.bak -e "print unless /^$id$,/"', $filetoopen);
}
The functionality of the -i command line argument can be accessed via $^I.
local #ARGV = $filetoopen;
local $^I = '.bak';
local $_;
while (<>) {
print if !/^$id$/;
}

Perl: Redirect STDOUT to two files

How can I redirect the STDOUT stream to two files (duplicates) within my Perl script? Currently I am just streaming into a single log file:
open(STDOUT, ">$out_file") or die "Can't open $out_file: $!\n";
What do I have to change? Thx.
You can also use IO::Tee.
use strict;
use warnings;
use IO::Tee;
open(my $fh1,">","tee1") or die $!;
open(my $fh2,">","tee2") or die $!;
my $tee=IO::Tee->new($fh1,$fh2);
select $tee; #This makes $tee the default handle.
print "Hey!\n"; #Because of the select, you don't have to do print $tee "Hey!\n"
And yes, the output works:
> cat tee1
Hey!
> cat tee2
Hey!
Use the tee PerlIO layer.
use PerlIO::Util;
*STDOUT->push_layer(tee => "/tmp/bar");
print "data\n";
$ perl tee_script.pl > /tmp/foo
$ cat /tmp/foo
data
$ cat /tmp/bar
data
File::Tee provides the functionality you need.
use File::Tee qw( tee );
tee(STDOUT, '>', 'stdout.txt');
If you're using a Unix-like system, use the tee utility.
$ perl -le 'print "Hello, world"' | tee /tmp/foo /tmp/bar
Hello, world
$ cat /tmp/foo /tmp/bar
Hello, world
Hello, world
To set up this duplication from within your program, set up a pipe from your STDOUT to an external tee process. Passing "|-" to open makes this easy to do.
#! /usr/bin/env perl
use strict;
use warnings;
my #copies = qw( /tmp/foo /tmp/bar );
open STDOUT, "|-", "tee", #copies or die "$0: tee failed: $!";
print "Hello, world!\n";
close STDOUT or warn "$0: close: $!";
Demo:
$ ./stdout-copies-demo
Hello, world!
$ cat /tmp/foo /tmp/bar
Hello, world!
Hello, world!

What is written in one file write to another

I have one file, and I need everything that is written in some time frame to that file to be written to a second file.
What is the best way to do so? Open some thread that will read the file and do so ?
Any ideas ?
The tee utility might be what you're looking for:
#! /usr/bin/perl
use warnings;
use strict;
my #files = qw/ file1 file2 /;
open my $fh, "| tee #files >/dev/null"
or die "$0: start tee failed: $!";
print $fh "$_\n" for map int rand 10, 1 .. 5;
close $fh or warn "$0: close tee: $!";
Sample run:
$ ./write-both
$ cat file1
0
7
5
8
2
$ cat file2
0
7
5
8
2
Sounds like a job for tail -f or the poor man's tail -f emulation.
Sounds like a job for File::Copy