Modifying Large files line by line using perl script - perl

I am having two huge .csv files one is around 8 GB and other is 3.4 GB file size. I want only few values from each line inside that .csv files.
Its taking huge time to modify the data and copy it into new file.
Could anyone help in modifying the code.So that the modification will be completed in a reasonable time.
Below is the lines of code:
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
require "$ENV{'SAI_HOME'}/bin/utils/Logging.pl";
require "$ENV{'SAI_HOME'}/bin/utils/Utilities.pl";
my $date1 = `date '+%d-%m-%Y_%H-%M-%Ss'`;
chomp($date1);
our $LOGPATH = "$ENV{'SAI_HOME'}/logs/SP6migrationcsv_$date1.log";
my $status = 0;
log_info("Refer $LOGPATH log file for more information");
my $csv = Text::CSV->new( { binary => 1, eol => $/, sep_char => ',' } );
my $file1 = $ARGV[0] or die "Please provide Subscriber and Subscription CSV files on the command line\n";
my $file2 = $ARGV[1] or die "Please provide Subscriber and Subscription CSV files on the command line\n";
my $subscriberFile = "";
my $subscriptionFile = "";
if ( ( grep /SUBSCRIBER/i, $file1 ) && ( grep /SUBSCRIPTION/i, $file2 ) ) {
$subscriberFile = $file1;
$subscriptionFile = $file2;
} elsif ( ( grep /SUBSCRIBER/i, $file2 ) && ( grep /SUBSCRIPTION/i, $file1 ) ) {
$subscriptionFile = $file1;
$subscriberFile = $file2;
} else {
log_error("Invalid CSV files input");
exit -1;
}
my $SP6DIR = `dirname $0`;
chomp $SP6DIR;
$SP6DIR = "${SP6DIR}/SP6";
`mkdir -p $SP6DIR` or checkExit( $?, "Unable to carete $SP6DIR directory" );
my $newSubscriberFile = "Subscriber.csv";
my $newSubscriptionFile = "Subscription.csv";
my $subscriptionimsifile = "$SP6DIR/.IMSI_$newSubscriptionFile";
my $subscriberimsifile = "$SP6DIR/.IMSI_$newSubscriberFile";
$newSubscriberFile = "${SP6DIR}/$newSubscriberFile";
$newSubscriptionFile = "${SP6DIR}/$newSubscriptionFile";
`dos2unix $subscriptionFile $subscriberFile 2>/dev/null`
or checkExit( $?, "Unable to perform dos2unix on input files" );
`cut -d "," -f3 $subscriptionFile > $subscriptionimsifile`
or checkExit( $?, "Failed to get IMSI details from $subscriptionFile" );
`cut -d "," -f1 $subscriberFile > $subscriberimsifile`
or checkExit( $?, "Failed to get IMSI details from $subscriberFile" );
my $isSubscriptionHeaderPresesnt = "false";
my $isSubscriberHeaderPresesnt = "false";
$status = system("head -1 $subscriptionimsifile | grep 'IMSI' >>/dev/null");
if ( $status == 0 ) {
$isSubscriptionHeaderPresesnt = "true";
}
$status = system("head -1 $subscriberimsifile | grep 'IMSI' >>/dev/null");
if ( $status == 0 ) {
$isSubscriberHeaderPresesnt = "true";
}
open( my $subscriptionData, '<:encoding(utf8)', $subscriptionFile )
or die "Could not open '$subscriptionFile' $!\n";
open( NEWSUBSCRIBERDATA, "> $newSubscriberFile" ) or die "Could not open '$newSubscriberFile' $!\n";
open( NEWSUBSCRIPTIONDATA, "> $newSubscriptionFile" ) or die "Could not open '$newSubscriptionFile' $!\n";
if ( "$isSubscriptionHeaderPresesnt" eq "true" ) {
my $subscriptionHeader = <$subscriptionData>;
if ( $csv->parse($subscriptionHeader) ) {
my #subscriptionHeaderFields = $csv->fields();
print NEWSUBSCRIPTIONDATA "\"$subscriptionHeaderFields[0]\",\"$subscriptionHeaderFields[2]\",\"$subscriptionHeaderFields[4]\",\"$subscriptionHeaderFields[5]\",\"$subscriptionHeaderFields[6]\",\"$subscriptionHeaderFields[8]\",\"$subscriptionHeaderFields[13]\",\"$subscriptionHeaderFields[14]\",\"$subscriptionHeaderFields[15]\",\"$subscriptionHeaderFields[16]\",\"$subscriptionHeaderFields[17]\",\"$subscriptionHeaderFields[18]\",\"$subscriptionHeaderFields[25]\",\"$subscriptionHeaderFields[26]\",\"$subscriptionHeaderFields[27]\"\n";
print NEWSUBSCRIBERDATA "\"IMSI\",\"IMEI\",\"MSISDN\",\"$subscriptionHeaderFields[21]\",\"$subscriptionHeaderFields[22]\",\"$subscriptionHeaderFields[12]\",\"$subscriptionHeaderFields[9]\",\"$subscriptionHeaderFields[1]\",\"$subscriptionHeaderFields[0]\"\n";
} else {
log_error("Line could not be parsed: $subscriptionHeader\n");
exit 1;
}
} else {
log_only("No header info in subscription file");
}
if ( "$isSubscriptionHeaderPresesnt" eq "false" && "$isSubscriberHeaderPresesnt" eq "true" ) {
print NEWSUBSCRIBERDATA "\"IMSI\",\"IMEI\",\"MSISDN\",\"CUSTOMER_SEGMENTATION\",\"CUST_SUBCATEGORY\",\"SUBS_TYPE\",\"SUBSCRIPTION_PLAN\",\"CONTRACT_IDREF\",\"SUBSCRIPTION_IDREF\"\n";
} else {
log_only("No header info in subscriber file");
}
my $subscriberHeader = "";
my #subscriptionFields = {};
my #subscriberFields = {};
while ( my $eachSubscriptionLine = <$subscriptionData> ) {
chomp $eachSubscriptionLine;
if ( $csv->parse($eachSubscriptionLine) ) {
#subscriptionFields = $csv->fields();
$status = system("grep \"^[\\\"]*${subscriptionFields[2]}[\\\"]*\\\$\" $subscriberimsifile >> /dev/null");
if ( $status == 0 ) {
my $lastMatchedSubscriberdata = `grep "^[\\\"]*${subscriptionFields[2]}[\\\"]*," $subscriberFile | tail -1`;
chomp $lastMatchedSubscriberdata;
if ( $csv->parse($lastMatchedSubscriberdata) ) {
#subscriberFields = $csv->fields();
if ( "${subscriberFields[0]}" eq "${subscriptionFields[2]}" ) {
#log_only("Updating \"#subscriberFields\" subscriber details from subscription data");
print NEWSUBSCRIBERDATA "\"$subscriberFields[0]\",\"$subscriberFields[1]\",\"$subscriptionFields[2]\",\"$subscriptionFields[21]\",\"$subscriptionFields[22]\",\"$subscriptionFields[12]\",\"$subscriptionFields[9]\",\"$subscriptionFields[1]\",\"$subscriptionFields[0]\"\n";
} else {
log_error("Unable to process #subscriberFields record");
exit -1;
}
} else {
log_error("Line could not be parsed: $lastMatchedSubscriberdata\n");
exit 1;
}
} else {
log_only("Adding new subscriber details from subscription : \"#subscriptionFields\"");
print NEWSUBSCRIBERDATA "\"$subscriptionFields[2]\",,\"$subscriptionFields[3]\",\"$subscriptionFields[21]\",\"$subscriptionFields[22]\",\"$subscriptionFields[12]\",\"$subscriptionFields[9]\",\"$subscriptionFields[1]\",\"$subscriptionFields[0]\"\n";
}
print NEWSUBSCRIPTIONDATA "\"$subscriptionFields[0]\",\"$subscriptionFields[2]\",\"$subscriptionFields[4]\",\"$subscriptionFields[5]\",\"$subscriptionFields[6]\",\"$subscriptionFields[8]\",\"$subscriptionFields[13]\",\"$subscriptionFields[14]\",\"$subscriptionFields[15]\",\"$subscriptionFields[16]\",\"$subscriptionFields[17]\",\"$subscriptionFields[18]\",\"$subscriptionFields[25]\",\"$subscriptionFields[26]\",\"$subscriptionFields[27]\"\n";
} else {
log_error("Line could not be parsed: $eachSubscriptionLine\n");
exit 1;
}
}
close(NEWSUBSCRIPTIONDATA);
open( my $subscriberData, '<:encoding(utf8)', $subscriberFile ) || die "Could not open '$subscriberFile' $!\n";
if ( "$isSubscriberHeaderPresesnt" eq "true" ) {
$subscriberHeader = <$subscriberData>;
}
while ( my $eachSubscriberLine = <$subscriberData> ) {
chomp $eachSubscriberLine;
if ( $csv->parse($eachSubscriberLine) ) {
#subscriberFields = $csv->fields();
$status = system("grep \"^[\\\"]*${subscriberFields[0]}[\\\"]*\\\$\" $subscriptionimsifile >>/dev/null");
if ( $status != 0 ) {
log_only(
"Adding back subscriber details, because unable to get IMSI details from subscription file : \"#subscriberFields\""
);
print NEWSUBSCRIBERDATA "\"$subscriberFields[0]\",\"$subscriberFields[1]\",\"$subscriberFields[2]\",\"$subscriberFields[6]\",,\"$subscriberFields[7]\",,,\n";
}
} else {
log_error("Line could not be parsed: $eachSubscriberLine\n");
exit 1;
}
}
close(NEWSUBSCRIBERDATA);
`sed -i -e '1 s|SUBSCRIPTION_ID|SUBSCRIPTION_IDREF|g' -e '1 s|SUBS_CATEGORY|SUBSCRIPTION_PLAN|g' -e '1 s|SUBS_STATE|SUBS_TYPE|g' -e '1 s|CUST_CATEGORY|CUSTOMER_SEGMENTATION|g' $newSubscriberFile`
or checkExit( $?, "Unable to update header info in subscriber fi le" );

General advice:
Don't use backticks to parse your input. Perl is perfectly capable of doing this with a while loop and split.
Misspelling variable names is going to screw you. Don't. isSubscriptionHeaderPresesnt
mixing your open calls - 3 argument with lexicals is generally preferred, but mismatching isn't nice.
Using the text string "false" in lieu of a boolean is horrible. Don't do it. Someone someday is going to do the equivalent of print "true" if "false" and it's going to break.
The most 'expensive' operation your script will be doing is reading the files. That's almost always true. So find something other than syscalls to grep or sed require full-rereading of the files you're targeting. Assuming subscriptionFile and subscriberFile are your biggies, you're reading them multiple times - you're running a cut that reads the whole thing. A dos2unix that reads the whole thing. A grep that reads the whole thing. And then you're opening it, and reading the whole thing.
your last line is a sed which will... re-read your output file, entirely, and apply a line by line transform to it.

Related

Use of uninitialized value $login_output in concatenation (.) or string at

in a .pl I have the following error (capture), the script is used through SPECTRUM, a network monitoring tool, and the script is used to capture the running config of a device, what could be the fault ? Thank you.
#!/opt/SPECTRUM/bin/perl -w
# This script will capture the running configuration of a
# Cisco SAN-OS device through an SSH session and print it to STDOUT.
#
# Error Codes:
# 0 = Success
# 255 = Usage error
# 254 = Invalid timeout value
# 252 = Login error
# 249 = Exec prompt not found error
# 244 = Error retrieving configuration
# 245 = Insufficient privileges
# 253 = Unexpected output
#
use strict;
use warnings;
use Net::SSH::Expect;
$ENV{'PATH'} = "/usr/bin:". $ENV{'PATH'};
### Main ###
if( $#ARGV != 4 && $#ARGV != 5 )
{
print "Usage: capture_running.pl <device IP> <user> <pass> <enable_pass>
<login_timeout_in_seconds> <capture_timeout_in_seconds>\n";
print STDERR "Usage: capture_running.pl <deviceIP> <user> <pass>
<enable_pass> <login_timeout_in_seconds> <capture_timeout_in_seconds>\n";
exit 255;
}
elsif( $ARGV[4] < 1 || $ARGV[4] > 600 )
{
print "$ARGV[4] is the login timeout and must be an int between 1 and 600 seconds\n";
print STDERR "$ARGV[4] is the login timeout and must be an int between 1 and 600 seconds\n";
exit 254;
}
elsif( $#ARGV == 5 && ( $ARGV[5] < 1 || $ARGV[5] > 600 ) )
{
print "$ARGV[5] is the capture timeout and must be an int between 1 and 600 seconds\n";
print STDERR "$ARGV[5] is the capture timeout and must be an int between 1 and 600 seconds\n";
exit 254;
}
else
{
my $capture_timeout = $ARGV[4];
if( $ARGV[5] )
{
$capture_timeout = $ARGV[5];
}
my $errorCode = 1;
my #data;
my $errorString = "\nHost $ARGV[0]: \n";
($errorCode, #data) = GetConfig( $ARGV[0], $ARGV[1], $ARGV[2], $ARGV[3],
$ARGV[4], $capture_timeout );
if( $errorCode == 0 )
{
# Success. The running configuration
# content is in the data variable
foreach ( #data ) { print "$_\n" }; # print the configuration to STDOUT
exit 0;
}
else
{
print STDERR $errorString;
if( $errorCode == 245 )
{
print STDERR join " ", #data, "\nEnsure that the device user has
sufficient privileges to disable paging and view the config\n";
}
else
{
print STDERR join " ", #data, "\n";
}
exit $errorCode;
}
}
exit 0;
sub GetConfig
{
my $deviceIP=shift;
my $user=shift;
my $pass=shift;
my $epass=shift;
my $login_timeout=shift;
my $capture_timeout=shift;
my #config;
my $msg;
my $ssh = Net::SSH::Expect->new ( host => $deviceIP,
user => $user,
password=> $pass,
raw_pty => 1,
no_terminal => 0,
timeout => $login_timeout,
ssh_option => '-1 -c DES'
);
my $login_output;
eval { $login_output = $ssh->login(); };
if( $# )
{
$msg = "Login has failed. Output: $login_output";
return( 252, $msg );
}
# login output should contain the right prompt characters
if( $login_output !~ /\>\s*\z/ )
{
$msg = "Login has failed. Didn't see device prompt as expected.";
$ssh->close();
return( 252, $msg );
}
if( $login_output !~ /\>\s*\z/ ) # Replace '#' is the prompt character here
{
# we don't have the '#' prompt, means we still can't exec commands
$msg = "Exec prompt not found.";
$ssh->close();
return( 249, $msg );
}
my $elogin = $ssh->exec("en");
my $elogin2 = $ssh->exec($epass);
if( $elogin2 !~ /\#\s*\z/ ) # Replace '#' is the prompt character here
{
$msg = "Exec prompt not found.";
$ssh->close();
return( 249, $msg );
}
# disable paging
# different commands for different devices, if they don't
# work then we will get messages about problems later
# specifically the "No prompt after 'sh run'" error
# errmsg doesn't get set when these error and if we use print
# and getlines to read for errors it causes problems with print "sh run"
# later.
# $ssh->exec( "term pager 0" );
my $paging = $ssh->exec( "term pager 0" );
if ( $paging =~ /\s?%\s/ )
{
$msg = "Unable to set terminal size to 0 - Insufficient privileges";
$ssh->close();
return( 245, $msg);
}
$ssh->send( "sh run" );
$ssh->timeout( $capture_timeout );
$ssh->peek(0);
while( my $line = $ssh->read_line() )
{
# get configuration content
if( $line !~
/sh run|Building configuration|Current configuration|^\s*$/ )
{
push #config, $line;
}
}
if( #config <= 0 )
{
$msg = "No data retrieved, the capture timeout may be too low.";
$ssh->close();
return( 244, $msg );
}
if( scalar grep { $_ =~ /^%/ } #config )
{
# Ensure show running actually returned the config and not an error
# message containing '%'
return( 245, #config );
}
return( 0, #config ); # everything was okay, return the captured data
}
It would really help us if you took the time to ensure the code you give us is well-formatted and as easy to read as possible.
But the code causing the problem is this:
my $login_output;
eval { $login_output = $ssh->login(); };
if( $# )
{
$msg = "Login has failed. Output: $login_output";
return( 252, $msg );
}
It's the only place where $login_output is used in a "concatenation (.) or string" as described in the error message.
So the the call to $ssh->login() is failing in such a way as to leave $login_output undefined.
I don't know anything about Net::SSH::Expect, but I suspect that you need to change the arguments to the new() call (a few lines above) in some way.
You'll get more information about what has gone wrong by adding $# to the debug output.
The most likely candidate for that error is this:
my $login_output;
eval { $login_output = $ssh->login(); };
if( $# )
{
$msg = "Login has failed. Output: $login_output"; # this line
return( 252, $msg );
}
Remove $login_output from that line since it will be uninitialized if login() dies/croaks. You can replace it with $# to get the message supplied to die/croak.

Perl - How extract file information for logrotate

i have following list of application log files (rotated) and i would get only new lines generated. For do this operation i've think to extract filename, inode and n. of rows from each file, for write it into a temporally file, who i would read each time before my elaboration (I am open to better solutions if you are).
This is my list of files:
root> ls -l
applog_s0.0.log
applog_s0.1.log
applog_s0.2.log
applog_s0.3.log
applog_s1.0.log
applog_s1.1.log
applog_s1.2.log
applog_s1.3.log
applog_s2.0.log
applog_s2.1.log
applog_s2.2.log
applog_s2.3.log
applog_s3.0.log
applog_s3.1.log
applog_s3.2.log
applog_s3.3.log
I can't just read the last log file in order of number, because it may have closed recently and I risk data losing.
This is my draft of script (draft because some instruction return compiled errors):
my $MY_DIR="/usr/cataclust/sharedfolder/logs/";
my %filelist;
# Load file list
foreach my $filename (glob("$MY_DIR/applog_s*.log")) {
my $ino = stat($filename); # Get inode of my file
my $nrows = $. ($filename); # this row doesn't work into script :( it works only by cmd line as perl -ne '}{ print $.' applog_s1.0.log
push( #{ $filelist { filename } }, $filename);
push( #{ $filelist { inode } }, $ino);
push( #{ $filelist { rows } }, $nrows);
}
# Elaborate log
foreach my $filename (glob("$IN_DIR/applog_s*.log")) {
open (FILE, $filename) or die "can't read open $filename";
$/ = "\n\n";
while( <FILE> ) {
my #rows = split /\n\n/;
my $ino = stat($filename);
if( $filename == $filelist{name} && $ino == $filelist{inode} ) {
if( $. < $filelist{rows} ) {
my $rown = $.;
if ($rows[$row] =~ m/\A\d.-\s(\d{8})\s(\d{2}:\d{2}:\d{2})\s-\s(\w+)\s-\s\/Extended Info/) {
if ($rows[$rown] =~ m/WARNING/ || $rows[$rown] =~ m/CRITICAL/ && $rows[$rown] !~ m/INFORMATION/) { # Shows only errors
my ($date, $time, $class, $message ) = $rows[$rown] =~ m/\A\d.-\s(\d{8})\s(\d{2}:\d{2}:\d{2})\s-\s(\w+)\s-\s\/Extended Info\n(\w.*)/;
push #evt, {date => $date, time => $time, classification => $class, information => $message};
}
}
}
}
}
}
This is log example:
0#- 20180403 11:11:11 - ERROR - /Extended Info
Fs Doesn't work...
1#- 20180403 11:12:13 - ERROR - /Extended Info
Fs Doesn't work...
could you help me to clarify?

Searching string in a multiline file using perl

I'm trying to find a match in a multi-line string using this script.
It works only when there's one row in the destination file.
I would like to know if there's any substitution for $_ in order to search a multi-line text?
#!/usr/bin/perl
my $time=`date +%D_%H:%M`;
chomp($time);
my $last_location=`cat /file.txt`;
chomp($last_location);
open (ERRORLOG, ">>/errors.log") || die "failed to open errorlog file \n$!\n\a";
open (MESSAGES, "</logfile") || die "failed to open alarms file \n$!\n\a";
seek(MESSAGES, 0, 2) || die "Couldn't seek to pos: 0 at end of file $!\n";
$end_position = tell(MESSAGES);
if ($end_position < $last_location) {
$last_location=0;
}
if ($end_position > $last_location) {
seek(MESSAGES, $last_location, 0) || die "Couldn't seek to pos: $last_location $! \n";
$num_of_messages_sent=0;
while (<MESSAGES>) {
chomp;
$line_to_check $_;
if ($line_to_check =~ /some text/ ) {
print ERRORLOG "$time: $line_to_check \n";
if ($num_of_messages_sent < 4) {
do something;
}
if ($num_of_messages_sent == 4) {
do something;
}
#increase counter
$num_of_messages_sent = $num_of_messages_sent + 1;
}
}
$last_location = tell(MESSAGES);
# print "last: $last_location , end: $end_position \n";
`echo $last_location >/file_last_location.txt`;
}
close (ERRORLOG);
close (MESSAGES);
Looks better this way:
while (my $line = <MESSAGES>) {
chomp($line);
print "line : $line\n";
if ($line =~ m!your_regexp_here!i){
print ERRORLOG "$time: $line_to_check \n";
$num_of_messages_sent++;
print "\tMATCH\tline: $line\n";
if ($num_of_messages_sent < 4){
print "Found $num_of_messages_sent matches\n";
}
}
}

Perl script.file handling issues

I have written a Perl script:
#!/usr/bin/perl
use strict;
use warnings;
my $file_name;
my $ext = ".text";
my $subnetwork2;
my %files_list = ();
opendir my $dir, "." or die "Cannot open directory: $!";
my #files = readdir $dir;
sub create_files() {
my $subnetwork;
open(MYFILE, 'file.txt');
while (<MYFILE>) {
if (/.subnetwork/) {
my #string = split /[:,\s]+/, $_;
$subnetwork = $string[2];
}
if (/.set/ && (defined $subnetwork)) {
my #string = split /[:,\s]+/, $_;
my $file = $subnetwork . $string[1];
open FILE, ">", "$file.text" or die $!;
close(FILE);
}
}
close(MYFILE);
}
sub create_hash() {
foreach (#files) {
if (/.text/) {
open($files_list{$_}, ">>$_") || die("This file will not open!");
}
}
}
sub init() {
open(MYFILE3, 'file.txt');
while (<MYFILE3>) {
if (/.subnetwork/) {
my #string3 = split /[:,\s]+/, $_;
$subnetwork2 = $string3[2];
last;
}
}
close(MYFILE3);
}
sub main_process() {
init;
create_files;
create_hash;
open(MYFILE1, 'file.txt');
while (<MYFILE1>) {
if (/.subnetwork/) {
my #string3 = split /[:,\s]+/, $_;
$subnetwork2 = $string3[2];
}
if (/.set/) {
my #string2 = split /[:,\s]+/, $_;
$file_name = $subnetwork2 . $string2[1] . $ext;
}
if (/.domain/ || /.end/ || ($. < 6)) {
my $domain = $_;
foreach (#files) {
if (/.text/ && /$subnetwork2/) {
prnt { $files_list{$_} } "$domain";
}
}
}
elsif ($. >= 6) {
print { $files_list{$file_name} } "$_";
}
}
close(MYFILE1);
foreach my $val (values %files_list) { close($val); }
closedir $dir;
}
main_process;
This script creates files in the current directory based upon the content of file.txt, and then open those files again.
Then it starts processing file.txt and redirects the lines according to the filename set dynamically.
This setting of the file name is also based upon the data in the file file.txt.
The problem that I am facing here is that the redirection is only to a single file. That means there is some problem with the file handle.
All the files that are expected to be created are created perfectly but the data goes into only one of them.
I doubt if there is a problem with the file handle that I am using while redirecting.
Could anyone please help?
Sample input file is below:
..cnai #Generated on Thu Aug 02 18:33:18 2012 by CNAI R21D06_EC01, user tcssrpi
..capabilities BASIC
.utctime 2012-08-02 13:03:18
.subnetwork ONRM_ROOT_MO:NETSim_BAG
.domain BSC
.set BAG01
AFRVAMOS="OFF"
AWBVAMOS="OFF"
ALPHA=0
AMRCSFR3MODE=1,3,4,7
AMRCSFR3THR=12,21,21
AMRCSFR3HYST=2,3,3
AMRCSFR3ICM=
AMRCSFR4ICM=
USERDATA=""
.set BAG02
AFRVAMOS="OFF"
AWBVAMOS="OFF"
ALPHA=0
AMRCSFR3MODE=1,3,4,7
AMRCSFR3THR=12,21,21
AMRCSFR3HYST=2,3,3
..end
The problem that i am facing is during execution:
> process.pl
Use of uninitialized value in ref-to-glob cast at process.pl line 79, <MYFILE1> line 6.
Can't use string ("") as a symbol ref while "strict refs" in use at process.pl line 79, <MYFILE1> line 6.
The problem i can understand is with this line:
print { $files_list{$_} } "$domain";
but i am unable to understand why!!
The output i need is :
> cat NETSim_BAGBAG01.text
.set BAG01
AFRVAMOS="OFF"
AWBVAMOS="OFF"
ALPHA=0
AMRCSFR3MODE=1,3,4,7
AMRCSFR3THR=12,21,21
AMRCSFR3HYST=2,3,3
AMRCSFR3ICM=
AMRCSFR4ICM=
USERDATA=""
> cat NETSim_BAGBAG02.text
.set BAG02
AFRVAMOS="OFF"
AWBVAMOS="OFF"
ALPHA=0
AMRCSFR3MODE=1,3,4,7
AMRCSFR3THR=12,21,21
AMRCSFR3HYST=2,3,3
>
Your problem in following lines:
open(PLOT,">>$_") || die("This file will not open!");
$files_list{$_}=*PLOT;
You should replace they with:
open($files_list{$_},">>$_") || die("This file will not open!");
This portion of your code is the key:
open(PLOT,">>$_") || die("This file will not open!");
$files_list{$_}=*PLOT;
The problem is that you are essentially using the filehandle PLOT as a global variable; every single entry in your hash is pointing to this same filehandle. Replace with something like this:
local *PLOT;
open(PLOT,">>$_") || die("This file will not open!");
$files_list{$_}=*PLOT;
You have got youself very entangled with this program. There is no need for the hash table or the multiple subroutines.
Here is a quick refactoring of your code that works with your data and writes files NETSim_BAG.BAG01.text and NETSim_BAG.BAG02.text. I put a dot between the subnet and the set to make the names a little clearer.
use strict;
use warnings;
my $out_fh;
open my $fh, '<', 'file.txt' or die $!;
my ($subnetwork, $set, $file);
while (<$fh>) {
if ( /^\.subnetwork\s+\w+:(\w+)/ ) {
$subnetwork = $1;
}
elsif ( /^\.set\s+(\w+)/ and $subnetwork) {
$set = $1;
$file = "$subnetwork.$set.text";
open $out_fh, '>', $file or die qq(Unable to open "$file" for output: $!);
print $out_fh;
}
elsif ( /^\.\.end/ ) {
undef $subnetwork;
undef $file;
}
if (/^[^.]/ and $file) {
print $out_fh $_;
}
}

Comparing filehandle with glob returned by IO::Select::can_read()

I am trying to manage three filehandles via IO::Select in perl. I have 1 input handle, 1 input/output handle, and 1 output handle. Im having a little trouble determining which filehandle is which when processing Select's return arrays of can_read() and can_write();
Example below
Any advice on how to actually compare these two filehandles? I've tried scalars, i've tried references, no references, etc. I can't think of why this isn't working.
#!/usr/bin/perl
use strict;
use warnings;
use IO::Select;
open(INPUT, "/dev/fd/3") or die "Unable to open input! $!";
my $stdin_buf;
# Main loop
while (1)
{
foreach my $read_fh ($select->can_read(10)) # This DOES return INPUT as being readable
{
if ($read_fh == \*INPUT) # THIS fails.
{
read($read_fh, $stdin_buf, 512);
}
}
}
I got it working. It was a combination of using references and eq (which i had tried prior to fixing references);
working code:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Select;
##############################################
# Asterisk to stream pipe thingie-ma-jig-bob #
# Written by Sean Powell - 10-5-10 #
##############################################
my $extension = $ARGV[0];
if (!$extension || $extension !~ /^\d+$/)
{
print "USAGE: Please provide a decimal extension as the first parameter";
exit(1);
}
my $ffmpeg = "/usr/bin/ffmpeg -f s16le -ar 8000 -ac 1 -i - -ab 64k -f mp3 -";
my $ezstream = "/usr/local/bin/ezstream -c /etc/asterisk/ICES/" . $extension . ".xml";
my $stdin_buf;
my $ffmpeg_buf;
my $last_activity = 0;
open(INPUT, "/dev/fd/3") or die "Unable to open input! $!";
open(FFMPEG, "|$ffmpeg") or die "Unable to fork off ffmpeg! $!";
open(EZSTREAM, "|$ezstream") or die "Unable to fork off ezstream! $!";
open(DEBUG, ">>/root/debug.log") or die "Unable to open debug log! $!";
my ($input_fh, $ffmpeg_fh, $ezstream_fh) = (*INPUT, *FFMPEG, *EZSTREAM);
my $select = new IO::Select(*INPUT);
$select->add(*FFMPEG);
$select->add(*EZSTREAM);
# Main loop
while (1)
{
foreach my $read_fh ($select->can_read(10))
{
print DEBUG "Filehandle can read: $read_fh - $input_fh - $ffmpeg_fh - $ezstream_fh\n";
if ($read_fh eq $input_fh)
{
my $read = read($read_fh, $stdin_buf, 512);
print DEBUG "Read off $read bytes from INPUT\n";
$last_activity = time();
}
if ($read_fh eq $ffmpeg_fh)
{
my $read = read($read_fh, $ffmpeg_buf, 512);
print DEBUG "Read off $read bytes from FFMPEG\n";
$last_activity = time();
}
}
foreach my $write_fh ($select->can_write(10))
{
if ($write_fh eq $ffmpeg_fh && length($stdin_buf) > 0)
{
my $size = length($stdin_buf);
my $wrote = syswrite($write_fh, $stdin_buf, $size);
while ($wrote < $size)
{
$wrote += syswrite($write_fh, $stdin_buf, $size - $wrote, $wrote);
}
print DEBUG "Wrote $wrote bytes to FFMPEG\n";
$last_activity = time();
$stdin_buf = undef;
}
if ($write_fh eq $ezstream_fh && length($ffmpeg_buf) > 0)
{
my $size = length($ffmpeg_buf);
my $wrote = syswrite($write_fh, $ffmpeg_buf, $size);
while ($wrote < $size)
{
$wrote += syswrite($write_fh, $ffmpeg_buf, $size - $wrote, $wrote);
}
$ffmpeg_buf = undef;
print DEBUG "Wrote $wrote bytes to EZSTREAM\n";
$last_activity = time();
}
}
last if (time() - $last_activity > 30);
}
close(INPUT);
close(EZSTREAM);
close(FFMPEG);
Use eq instead of == for this kind of comparison.
if ($read_fh eq *INPUT) { ... }