issue with creating perl script to imitate linux command "ifconfig" - perl

I have an assignment in which I am to create a Perl script in Linux to imitate the command ifconfig. This command basically shows you information about your network interfaces. I have already created the program, but a few lines are giving me some issues, I would appreciate if anyone could correct the code for me. The errors I am getting says that $get_iface_data requires an explicit package name at line 8, however I do not know how to declare that.
#!/usr/bin/perl
use strict;
use warnings;
use Net::Int::Stats;
use Net::Ifconfig::Wrapper;
my $Iface = $ARGV[0];
my $rx_packets = $get_Iface_data->value($Iface, 'rx_packets');
my $Iface_Info = Net::Ifconfig::Wrapper::Ifconfig('list', '', '', '');
print "\tether ". $Iface_Info->{$Iface}{'ether'}."\n";
My assignment basically requires me to get an interface as input, and display the info about that interface, as the ifconfig command would do. I also used two packages, Net::Int::Stats and Net::Ifconfig::Wrapper. The only difference between my script and the ifconfig command is my script will require an interface as parameter

Well, where do you defined $get_Iface_data?
The $foo->bar is a method call syntax. This means that $foo is some sort of object and bar is a method that can be used on that object.
Do you understand Object Oriented Programming and how Perl uses it? Perl has an excellent tutorial to help you get started.
What it comes done to is that you can't use a particular method (think subroutine) except on an object of that class. From this snippet of code, and what your error states, you never defined $get_Iface_data, so you have to define it. In this case, you have to create the object:
my $get_Iface_data = Net::Int::Stats->new();
Now, you can use the various Net::Int::Stats methods on the %get_Iface_data object:
my $rx_packets = $get_Iface_data->value($Iface, 'rx_packets');

You are just missing the line where you create the Net::Int::Stats object:
#!/usr/bin/perl
use strict;
use warnings;
use Net::Int::Stats;
use Net::Ifconfig::Wrapper;
my $Iface = $ARGV[0];
my $get_Iface_data = Net::Int::Stats->new();
my $rx_packets = $get_Iface_data->value($Iface, 'rx_packets');
my $Iface_Info = Net::Ifconfig::Wrapper::Ifconfig('list', '', '', '');
print "\tether ". $Iface_Info->{$Iface}{'ether'}."\n";

Related

Calling one Perl program from another

I have two Perl files and I want to call one file from another with arguments
First file a.pl
$OUTFILE = "C://programs/perls/$ARGV[0]";
# this should be some out file created inside work like C://programs/perls/abc.log
Second File abc.pl
require "a.pl" "abc.log";
# $OUTFILE is a variable inside a.pl and want to append current file's name as log.
I want it to create an output file with the name of log as that of current file.
One more constraint I have is to use $OUTFILE in both a.pl and abc.pl.
If there is any better approach please suggest.
The require keyword only takes one argument. That's either a file name or a package name. Your line
require "a.pl" "abc.log";
is wrong. It gives a syntax error along the lines of String found where operator expected.
You can require one .pl file from another .pl, but that is very old-fashioned, badly written Perl code.
If neither file defines a package then the code is implicitly placed in the main package. You can declare a package variable in the outside file and use it in the one that is required.
In abc.pl:
use strict;
use warnings;
# declare a package variable
our $OUTFILE = "C://programs/perls/filename";
# load and execute the other program
require 'a.pl';
And in a.pl:
use strict;
use warnings;
# do something with $OUTFILE, like use it to open a file handle
print $OUTFILE;
If you run this, it will print
C://programs/perls/filename
You should convert your perl file you want to call to a perl module:
Hello.pm
#!/usr/bin/perl
package Hello;
use strict;
use warnings;
sub printHello {
print "Hello $_[0]\n"
}
1;
Then you can call it:
test.pl
#!/usr/bin/perl
use strict;
use warnings;
# you have to put the current directory to the module search path
use lib (".");
use Hello;
Hello::printHello("a");
I tested it in git bash on windows, maybe you have to do some modifications in your environment.
In this way you can pass as many arguments as you would like to, and you don't have to look for the variables you are using and maybe not initialized (this is a less safe approach I think, e.g. sometimes you will delete something you did't really want) somewhere in the file you want to call. The disadvantage is that you need to learn a bit about perl modules but I think it definitely worths.
A second approach could be to use the exec/system call (you can pass arguments in this way too; if forking a child process is acceptable), but that is an another story.
I would do this another way. Have the program take the name of the log file as a command-line parameter:
% perl a.pl name-of-log-file
Inside a.pl, open that file to append to it then output whatever you like. Now you can run it from many other sorts of places besides another Perl program.
# a.pl
my $log_file = $ARGV[0] // 'default_log_name';
open my $fh, '>>:utf8', $log_file or die ...;
print { $fh } $stuff_to_output;
But, you could also call if from another Perl program. The $^X is the path to the currently running perl and this uses system in the slightly-safer list form:
system $^X, 'a.pl', $name_of_log_file
How you get something into $name_of_log_file is up to you. In your example you already knew the value in your first program.

How can I pass variables from one CGI script to another?

I have a CGI perl script called install-app-pl.cgi:
#!/usr/bin/perl -w
print header('text/html');
use strict;
use CGI ':standard';
# Get me some vars
my #params = param();
my $APP_NAME = param('app_name');
my $APP_WEB_PORT = param('app_web_port');
my $APP_WEB_USER = param('app_web_user');
my $APP_WEB_PASS = param('app_web_pass');
my $DOWNLOAD_DIR = param('download_dir');
my $CONFIG_DIR = param('config_dir');
my $LIBRARY_DIR = param('library_dir');
my $TEMP_DOWNLOAD_DIR = param('temp_download_dir');
# Run another script
if ( $APP_NAME ) {
print "Installing $APP_NAME...";
print "<pre>";
system ("perl /var/www/mysite.local/public_html/lib/$APP_NAME/install-$APP_NAME.pl");
print "</pre>" ;
}
else {
print "No app specified, check the error log";
}
I'm trying to get it to pass the variables defined from the CGI parameters to install-$APP_NAME.pl
#!/usr/bin/perl -w
print header('text/html');
use strict;
use CGI ':standard';
require "/var/www/mysite.local/public_html/cgi-bin/install-app-pl.cgi"
# Echo my vars
print "$CONFIG_DIR $DOWNLOAD_DIR $LIBRARY_DIR $PGID $PUID $TZ $APP_WEB_PORT";
But I'm not sure of the best way to pass those on.
Are you sure that install-app-pl.cgi is a CGI program? Are you sure that it's not just a Perl command-line program? I mean, I see how it's named, but it seems very strange to call a CGI program using system() like that.
And the difference is crucial here. CGI programs access their parameters in a different way command-line programs.
If it really is a CGI program, then you have a few options:
Make an HTTP request to it (using something from the LWP bundle of modules).
Use CGI.pm's debugging mechanism to call it the same way as you're currently calling it, but passing the CGI parameters like foo=xxx&bar=yyy&baz=zzz (see the DEBUGGING section of the CGI.pm documentation for details). This, of course, relies on the program using CGI.pm and it feels a bit hacky to me.
Ask yourself if the program really needs to be a CGI program if you're calling from another program using system(). And then decide to rewrite it as a command-line program. If you want both a CGI version and a command-line version, then you could move most of the code to a module which could be used by two thin wrappers which just extract the parameters.
A few other points about your code.
Perl 5.6 (released in 2000) introduced a use warnings pragma. Most people now use that in place of -w on the shebang line.
It seems weird to call the header() function before loading the CGI module that defines it. It works, because the use is handled at compile time, but it would be nice to re-order that code to make more sense.
Similarly. most people would have use strict (and use warnings) as the very first things in their program. Immediately after the shebang line.
system() returns the return value from the process. If your second program produces useful output that you want displayed on the web page, you should use backticks instead.
If all of your output is going to be in a <pre> element, why not just remove that element and return a content type of "text/plain" instead?
Update: And I'd be remiss if I didn't reiterate what many people have already said in comments on your original question - this sounds like a terrible idea.

How to make use of UUIDGEN of unix in perl script

I am trying to generate a unique number using uuidgen (of unix). The generated unique number should get stored in a variable. When i am doing it in a function , I am facing errors.
Can anyone let me know how to make use of uuidgen script in perl.
#!/usr/bin/perl
sub function_uuidgen
{
my myuuid;
system(`export myuuid=uuidgen`);
print "\n unique id is : $myuuid";
# I need not to export the variable, I just need to unique number generated by UUID GENERATOR in a variable.
}
int main
{
print "\n I am in main function";
&function_uuidgen;
}
I am facing the below error when I am running uuidgen as mentioned below. Can anybody help me out with exporting the JAVA VARIABLE in perl ? How to export the path variable,in case if this error is related to that.
Error :
/bin/java: uuidgen 1: not found
Code :
sub function_uuidgen
{
my $myuuid = qx(uuidgen);
chomp $myuuid;
print "\n unique id is : $myuuid";
# I need to export the variable, as it is giving me error without exporting.
}
int main
{
print "\n I am in main function";
function_uuidgen();
}
You're mixing up C and Perl here.
As far as I know you can't access exportet system variables that way from perl (correct me if I am wrong. I don't have much knowledge of linux system variables).
A way to generate UUID's would be the Data::GUID Module from CPAN
use strict;
use warnings;
use Data::GUID qw( guid_string );
my $guid = guid_string();
print "$guid\n";
Also Perl doesn't have an int main function. Your code starts at the top and runs down to the bottom. Of course this gets a bit different if you create an object orientated module.
If you for some reason can't use Data::GUID, this is a way to use the output of uuidgen (note the backticks):
#!/usr/bin/perl
use strict;
use warnings;
my $uuid=`uuidgen`;
chomp $uuid;
print "$uuid\n";
Example output:
$ ./hep.pl
fe82c4f6-a1f2-4242-ab45-853780931927
$
Also, using & before function calls went out of fashion many years ago :-)
Without knowing anything about uuidgen: You could just
my $perlVar = `uuidgen`;
within perl.
Assuming calling uuidgen in your console returns the number you are looking for.
export is a shell command that adds a variable and value to its environment block. The environment block is private to a process, but (by default) copied to a child process. You appear to be thinking it is some sort of global area - it is not.
So, all you would be doing is adding a value to the shell's environment block, not your own! (That's the shell created by system(), not the one you were running from). Placing the export inside back-ticks is strange, if not wrong.
Easier to use:
my $myuuid = qx(uuidgen);
chomp $myuuid;
Notice I am using qx instead of back-ticks `` because they can be confusing (back-ticks are deprecated in UNIX shells as well).
To run the subroutine, loose the C style int main:
print "\n I am in ", __PACKAGE__, "package\n";
function_uuidgen();
The leading & on a subroutine call has side-effects that you probably don't need.

In Perl, how do I send CGI parameters on the command line?

Normally i get the data from a webpage but i want to send it from the command line to facilitate debugging.
To get the data i do something like:
my $query = new CGI;
my $username = $query->param("the_username");
this doesn't seem to work:
$ ./script.pl the_username=user1
EDIT:
Actually the above works. The if statement that checked $username was wrong (using == instead of eq).
As I found out long time ago, you can indeed pass query string parameters to a script using CGI.pm. I am not recommending this as a preferred debugging method (better to have replicable stuff saved in files which are then directed to the STDIN of the script), however, it does work:
#!/usr/bin/env perl
use warnings; use strict;
use CGI;
my $cgi = CGI->new;
my $param_name = 'the_username';
printf(
"The value of '%s' is '%s'.\n",
$param_name, $cgi->param($param_name)
);
Output:
$ ./t.pl the_username=yadayada
The value of 'the_username' is 'yadayada'.
CGI reads the variables from standard input.
See this part of the CGI.pm documentation:
http://search.cpan.org/dist/CGI/lib/CGI.pod#DEBUGGING

How can I share global values among different packages in Perl?

Is there a standard way to code a module to hold global application parameters to be included in every other package? For instance: use Config;?
A simple package that only contains our variables? What about readonly variables?
There's already a standard Config module, so choose a different name.
Say you have MyConfig.pm with the following contents:
package MyConfig;
our $Foo = "bar";
our %Baz = (quux => "potrzebie");
1;
Then other modules might use it as in
#! /usr/bin/perl
use warnings;
use strict;
use MyConfig;
print "Foo = $MyConfig::Foo\n";
print $MyConfig::Baz{quux}, "\n";
If you don't want to fully qualify the names, then use the standard Exporter module instead.
Add three lines to MyConfig.pm:
package MyConfig;
require Exporter;
our #ISA = qw/ Exporter /;
our #EXPORT = qw/ $Foo %Baz /;
our $Foo = "bar";
our %Baz = (quux => "potrzebie");
1;
Now the full package name is no longer necessary:
#! /usr/bin/perl
use warnings;
use strict;
use MyConfig;
print "Foo = $Foo\n";
print $Baz{quux}, "\n";
You could add a read-only scalar to MyConfig.pm with
our $READONLY;
*READONLY = \42;
This is documented in perlmod.
After adding it to #MyConfig::EXPORT, you might try
$READONLY = 3;
in a different module, but you'll get
Modification of a read-only value attempted at ./program line 12.
As an alternative, you could declare in MyConfig.pm constants using the constant module and then export those.
Don't use global variables for configuration and don't sotre configuration as code. I have an entire chapter in Mastering Perl about this.
Instead, make a configuration class that any other package can use to access the configuration data. It will be much easier in the long run to provide an interface to something you may want to change later than deal with the nuttiness you lock yourself into by scattering variables names you have to support for the rest of your life.
A config interface also gives you the benefit of composing new answers to configuration questions by combining the right bits of actual configuration data. You hide all of that behind a method and the higher levels don't have to see how it's implemented. For instance,
print "Hello!" unless $config->be_silent;
The be_silent answer can be triggered for multiple reasons the higher-level code doesn't need to know about. It could be from a user switch, that the program detected it is not interactive, and so on. It can also be flipped by options such as a debugging switch, which overrides all other preferences. No matter what you decide, that code line doesn't change because that statement only cares about the answer, not how you got the answer.