ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I have a small perl script which has 3 subroutines a,b, and c in it . An Array (lets call it X) has the names of these subroutines stored in it ,using foreach i am reading out each and every name of the subroutine from the array. My Question is how do i make sure that a subroutine of that name is executed when ever the element from the array is read,For Ex: When subroutine b is read and printed out from the array i want the respective subroutine B to be executed .Hope you ppl got my Question
I need this logic for someother script,i am just pasting a proto-type here.
Code:
#!/usr/bin/perl
use strict;
use warnings;
my @x=("a","b","c");
foreach my $val(@x)
{
print "This is $val\n";
}
sub a
{
print "This is AAA";
}
sub b
{
print "This is BBB";
}
sub c
{
print "This is CCC";
}
OUTPUT:
In the foreach block i want to write a do statement and execute the corresponding subroutine returned.
This is a (At this point must call subroutine a)
This is b (At this point must call subroutine b)
This is c ( (At this point must call subroutine c)
It sounds to me like you want to use a variable as a variable name (a.k.a. a symbolic reference). This is a very bad idea; see this post (and its follow-ups) for why.
However, it's easy to store subroutines as items in an array by using references in Perl:
Code:
#!/usr/bin/perl
use strict;
use warnings;
my @funcs = (\&a, \&b, \&c);
for my $func (@funcs) {
$func->();
}
sub a {
print "This is AAA\n";
}
sub b {
print "This is BBB\n";
}
sub c {
print "This is CCC\n";
}
Note that for subroutines this simple, you can actually simply leave them anonymous and insert them directly into the array (without naming them separately anywhere):
Code:
#!/usr/bin/perl
use strict;
use warnings;
my @funcs = (
sub { print "This is AAA.\n"; },
sub { print "This is BBB.\n"; },
sub { print "This is CCC.\n"; },
);
for my $func (@funcs) {
$func->();
}
For more on using subroutines and references together this way, see this link.
Last edited by Telemachos; 10-26-2009 at 05:35 PM.
Thanks a lot telemachos,its working. I just have few questions,i'm new to perl. Why doesn't it work when i remove the double quotes inside the array. I meant like my @x=("\&a","\&b","\&c"); since its an array.
Secondly,what does $func->(); mean. May be if you can tell me what i should google for to know more about it.Thanks Again. Cheers :-)
EDIT:
I was trying this,instead of using print statements in subroutines,i was trying to execute a block of code,for example starting some application. like firefox and thunderbird . The problem i ran into is when sub a is executed( it loads an application say firefox),for sub b to be executed(which will load thunderbird) i have to first close firefox,how can i make sure that thunderbird is open along with firefox SOrry if am asking for too much. Thanks Again.
Thanks a lot telemachos,its working. I just have few questions,i'm new to perl. Why doesn't it work when i remove the double quotes inside the array. I meant like my @x=("\&a","\&b","\&c"); since its an array.
You shouldn't need (and don't want) quotes there. The backslash does a number of things in Perl, but here it's the take a reference to operator. So you should be able to do this:
Code:
my $code_ref = \&sub_name;
That assigns a reference to the subroutine named 'sub_name' to the variable $code_ref. What we're doing in the case of the array is assigning a reference to a subroutine as each item in the three-item array. No quotes are needed. See here and here for more on this.
Quote:
Originally Posted by kdelover
Secondly,what does $func->(); mean.
In the for loop there, $func is aliased to each item in the array in turn. Since each of the things in the array is a reference to a subroutine, you can't simply put it in quotes and print it. You have to dereference it, in order to actually call the subroutine. To do this we use the arrow syntax:
Code:
$code_ref->(@args)
Inside the parens, you can (optionally) place arguments. Since our subroutines don't take arguments, we just say $func->()
Using subroutines in references is probably an intermediate-level Perl thing. You might want to start by reading up on references period and then getting into this. I would recommend these four links, in this order:
awesomeee man!! Thanks a lot for the explanation and the links,the link you gave perltraining.com.au its awesome,i have bookmarked it Thanks again Cheers!!!
I just saw your follow-up, and my instinct is to say that Perl is great for a lot of things, but I don't think I would use it as a program launcher.
What makes you say this? Is there something different about the way Perl does a fork() + exec() than does any other language (including shells), at least in a Linux/UNIX environment? Not disputing your assertion; just want to understand your reasoning.
--- rod.
What makes you say this? Is there something different about the way Perl does a fork() + exec() than does any other language (including shells), at least in a Linux/UNIX environment? Not disputing your assertion; just want to understand your reasoning.
--- rod.
Hmm, well to be honest, I wasn't saying that it would be impossible or even bad to do it in Perl. It was a quick response - just my first thought - and my reason was that if I'm going to be working with a lot of system calls and/or signals, I might probably choose to go lower-level than Perl. That said, I would probably really choose to let someone else code it and use one of the many launchers out there.
So maybe this was just a failure of imagination on my part.
My main intention was to write a application-launcher script,that would pop-up after the user logs in and it would show a GUI window using zenity ( which a checklist) and the user would select what all applications he wants to start. I am sorry i dont have the code at the moment to paste here
One problem i ran into is,lets say if user selects three applications a,b,and c, from the checkbox,am storing the name of those apps in a variable called $Select="a:b:c"( where : is a separator bt.the names) and then using a split function to remove the ":" and store the names of the apps in an array called @apps (@apps="a,b,c").Using foreach i want read out the name of each application name( This infact would be the name of a subroutine being called) and i want that application to be launched.But i dont understand how do i do this since the array must have a reference to the subroutine. The Q is simple,the user would select the application to be started,but selecting and the corresponding subroutine should be called. Hope i made my point clear :-D
my $choice="a:b:c";
my $arr=split(":",$choice);
foreach (@arr)
{
$_->();
}
There are lots of ways to handle this, but here's one: add another layer of indirection. That is, don't think of the user as directly choosing applications to launch. Instead, set up a situation where the user selects from a set of options that you give him or her:
Code:
What apps do you want to launch?
(1) Firefox
(2) Thunderbird
(3) Mutt
(4) Gvim
The user enters (say) the numbers, and the numbers go into an array, say called @choices. You, however, have already (cleverly) created a hash that uses the numbers 1-4 as keys and the corresponding function calls as code references. You loop over the items in @choices, using those to get at the function calls in the hash. Of course, since you can't trust the user to give you reasonable input, you also have to filter what you get.
Here's a mockup of some of this to give you an idea of what I mean.
Code:
#!/usr/bin/env perl
use strict;
use warnings;
my %choice_calls = (
1 => sub { print "start Firefox\n" },
2 => sub { print "start Thunderbird\n" },
3 => sub { print "start Mutt\n" },
4 => sub { print "start Gvim\n" }
);
print "Give me a colon-separated list of choices:\n";
print "\t(1) Firefox\n";
print "\t(2) Thunderbird\n";
print "\t(3) Mutt\n";
print "\t(4) Gvim\n";
chomp(my $choice_string = <STDIN>);
my @choices = split /:/, $choice_string;
my @good_choices = grep { exists $choice_calls{$_} } @choices;
my @bad_choices = grep { !exists $choice_calls{$_} } @choices;
for my $choice (@good_choices) {
$choice_calls{$choice}->();
}
if (@bad_choices) {
print "\nBy the way, you also gave these bad choices.\n";
print "Please type more carefully in the future: @bad_choices.\n"
}
If you run this and enter something like 1:4:9, you can get an idea of the way it might work. (Note that I have no idea how Zenity works. It may add some helpful menu/choice creating stuff that I'm not thinking of.)
Also, by the way, I officially apologize for the variable names. I'm too tired to be more creative right now, so they're all variations of 'choice'. Think of it as a negative example: don't clutter up your namespace with nothing but variations of one variable name!
Last edited by Telemachos; 10-27-2009 at 06:56 PM.
It comes very handy while taking user-inputs.I'll Try out the script you mentioned,i wonder if i can do it along with zenity :-).Is there any way i can add a /& explicitly into the array to create a reference.
By the way Thanks again for that perl site,i have downloaded couple of Pdfs from there on perl for system admins,its really great,concise and at the same time very informative :-)
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.