How to pass index of array in cmd line argument which is function pointer and call to specific function in perl? - arrays

Suppose I have 2 functions in Perl. I would create a array of references of that two functions. & in command line argument I'll pass only that index of array which call specific function and if I don't give any argument then it'll call all functions which referenced were in array(Default case).
So, can any help me to do this?
## Array content function pointers
my #list= {$Ref0,$Ref1 }
my $fun0Name = “fun0”;
my $Ref0 =&{$fun0Name}();
my $fun1Name = “fun1”;
my $Ref1 =&{$fun1Name}();
#### Two functions
sub fun0() {
print "hi \n";
}
sub fun1() {
print "hello \n";
}
##### Now in cmd argument if i passed Test.pl -t 0(index of array ,means call to 1st function)
##### if i give test.pl -t (No option ) ....then i call both function.

Creating a function pointer (called a code reference in Perl) is easy enough:
sub foo {
say "foo!";
}
sub bar {
say "bar!";
}
my $foo_ref = \&foo;
my $bar_ref = \&bar;
Putting things in an array is pretty easy:
my #array = ( $foo_ref, $bar_ref );
Reading arguments from the command line is pretty easy:
my $arg = shift #ARGV;
Looking things up in an array is also pretty easy:
my $item = $array[$arg];
Which part are you having trouble with?

Related

Passing array arguments to Perl subroutine

I am new to perl programming and I am trying to build a script using several subroutines on it. For a start I am trying to run a short mocke script to work out subroutines behaviour, but I don't get to understand the input.
Here is my code:
sub prueba{
my (#array1, #array2)=#_;
if (scalar(#array1)<scalar(#array2)) {
print #array1,"\n";
} elsif (scalar(#array1)>scalar(#array2)){
print #array2,"\n";
}
};
my #primero=(1,5,9);
my #segundo=(1,7,8,9,6,5,6,9);
prueba(#primero,#segundo);
I am passing two arrays and I want the subroutine to retrieve the answer according to those arrays, but when I run it I get no output, not even warning errors messages... I already tried using the refference to the array, but still not working:
sub prueba{
my (#array1, #array2)=#_;
if (scalar(#array1)<scalar(#array2)) {
print #array1,"\n";
} elsif (scalar(#array1)>scalar(#array2)){
print #array2,"\n";
}
};
my #primero=(1,5,9);
my #segundo=(1,7,8,9,6,5,6,9);
prueba(\#primero,\#segundo);
You can't pass arrays to subs (and they can't return them). You can only pass a number of scalars. What you are doing is equivalent to the following:
prueba(1,5,9,1,7,8,9,6,5,6,9);
All of the arguments end up in #array1. What we do is pass references to arrays.
prueba(\#primero,\#segundo);
But that also requires changing the sub. Without change, all of the arguments still end up in #array1. See perlreftut for a start on working with references. You can use
sub prueba{
my ($array1, $array2)=#_;
if (scalar(#$array1)<scalar(#$array2)) {
print "#$array1\n";
} elsif (scalar(#$array1)>scalar(#$array2)){
print "#$array2\n";
}
}
or just
sub prueba {
my ($array1, $array2) = #_;
if (#$array1 < #$array2) { say "#$array1"; }
elsif (#$array1 > #$array2) { say "#$array2"; }
}
< and > expect a number, so they already impose scalar context. And might as well use say, though that requires use feature qw( say ); (or something like use 5.014; which does the trick as well).
You can use prototypes to make it look like you're passing multiple arrays, and have perl turn them automatically into references:
sub prueba :prototype(\#\#) {
my ($array1, $array2) = #_;
if (#$array1 < #$array2) {
print #$array1,"\n";
} elsif (#$array1 > #$array2){
print #$array2,"\n";
}
}
my #primero=(1,5,9);
my #segundo=(1,7,8,9,6,5,6,9);
prueba(#primero, #segundo);
But read the documentation carefully to understand the cases where the subroutine can be called without enforcing the prototype.
Thanks all I just figured out what I wanted. I found that I can actually pass an array to perl, however maybe I am not explaning mysfel properly.The thing is to load the arrays as follow, inside the subroutine.
my #primero=#{$_[0]};
my #segundo=#{$_[1]};
This means we are using the reference. Ehen running the function, we must write the \ before each input:
prueba(\#primero,\#segundo);

How to return an array from read command in a function?

I have a small problem in here with bash
I wrote an array in a simple function and I need to return it as an array with read command and also need to call it somehow.
function myData {
echo 'Enter the serial number of your items : '
read -a sn
return ${sn[#]}
}
for example like this ???
$ ./myapp.sh
Enter the serial number of your items : 92467 90218 94320 94382
myData
echo ${?[#]}
Why we don't have return value in here like other languages ?
thanks for your help...
As others mention, the builtin command return is intended to send the exit status to the caller.
If you want to pass the result of processing in the function to the
caller, there will be several ways:
Use standard output
If you write something to the standard output within a function, the output
is redirected to the caller. The standard output is just a non-structured
stream of bytes. If you want to make it have a special meaning such as an
array, you need to define the structure by assigning a delimiter to some
character(s). If you are sure each element do not contain space, tab, or
newline, you can rely on the default value of IFS:
myfunc() {
echo "92467 90218 94320 94382"
}
ary=( $(myfunc) )
for i in "${ary[#]}"; do
echo "$i"
done
If the elements of the array may contain whitespace or other special
characters and you need to preserve them (such a case as you are handling
filenames), you can use the null character as the delimiter:
myfunc() {
local -a a=("some" "elements" "contain whitespace" $'or \nnewline')
printf "%s\0" "${a[#]}"
}
mapfile -d "" -t ary < <(myfunc)
for i in "${ary[#]}"; do
echo ">$i" # The leading ">" just indicates the start of each element
done
Pass by reference
As other languages, bash>=4.3 has a mechanism to pass the variable by
reference or by name:
myfunc() {
local -n p="$1" # now p refers to the variable with the name of value of $1
for (( i=0; i<${#p[#]}; i++ )); do
((p[i]++)) # increment each value
done
}
ary=(0 1 2)
myfunc "ary"
echo "${ary[#]}" # array elements are modified
Use the array as a global variable
Will be needless to explain its usage and pros/cons.
Hope this helps.

Can I create an array of functions in Powershell?

I would like to have an array that contains a set of functions that I can iterate through and call. The issue is that the functions all run via the line that adds them to the array (ie. $scripts).
Example:
function Hello
{
$BadFunction = "Hello"
Write-Host "Hello!"
}
function HowAreYou
{
$BadFunction = "HowAreYou"
Write-Host "How are you?"
#$false = $true
}
function Goodbye
{
$BadFunction = "Goodbye"
Write-Host "Goodbye!"
}
$scripts = #((Hello), (HowAreYou), (Goodbye))
foreach ($script in $scripts)
{
$script
}
Functions can only be called by using their name, not referenced, but you can get the scriptblock via the Function: drive:
$scripts = $Function:Hello, $Function:HowAreYou, $Function:GoodBye
# call them with the & operator
$scripts | ForEach-Object { & $_ }
# You can also call them by calling Invoke on the scriptblock
$scripts | ForEach-Object Invoke
Joey's answer contains good information, but if all you need is to reference your functions by name, define your array as containing the function names as strings, and invoke the functions by those strings with &, the call operator:
function Hello { "Hello!" }
function HowAreYou { "How are you?" }
function Goodbye { "Goodbye!" }
# The array of function names *as strings*.
# Note that you don't need #(...) to create an array.
$funcs = 'Hello', 'HowAreYou', 'Goodbye'
foreach ($func in $funcs)
{
# Use & to call the function by the name stored in a variable.
& $func
}
The issue is that the functions all run via the line that adds them to the array (ie. $scripts).
That's because your array elements are expressions (due to the enclosing (...)) that call the functions (e.g., (Hello) calls Hello and makes its output the array element), given that they're being referenced without single- or double-quoting.
Unlike in, say, bash, you cannot define string array elements as barewords (tokens without enclosing single- or double-quoting); for instance, the following is a syntax error in PowerShell:
# !! Does NOT work - strings must be quoted.
$funcs = Hello, HowAreYou, GoodBye # ditto with #(...)

get param function array in perl

I want to get the array that I send in my function but it seem's to be empty.
I call send_file(); with an array in the param
send_file($addr, #curfile);
And this is the way I get back the param
sub send_file($$)
{
my $addr = $_[0];
my #elem = #_;
...
}
Why my #elem is empty ? How could I get back the array without losing everything ?
Don't use prototypes. Their purpose is to change parsing of the source which you don't need.
sub send_file
{
my $addr = shift;
my #elem = #_;
...
}
send_file($addr, #curfile);
You should pass your array by reference instead:
#!/usr/bin/perl
use strict;
use warnings;
my $test_scalar = 10;
my #test_array = qw(this is a test);
sub test($\#)
{
my ($scalar, $array) = #_;
print "SCALAR = $scalar\n";
print "ARRAY = #$array\n";
}
test($test_scalar, #test_array);
system 'pause';
Output:
SCALAR = 10
ARRAY = this is a test
Press any key to continue . . .
EDIT:
If you would like to do the same thing without passing by reference change your $$ to $# and use shift so the first argument doesn't end up included in your array. Passing arrays by reference is better coding practice though . . . This is just to show you how it can be done without passing by reference:
#!/usr/bin/perl
use strict;
use warnings;
my $test_scalar = 10;
my #test_array = qw(this is a test);
sub test($#)
{
my ($scalar, #array) = #_;
print "SCALAR = $scalar\n";
print "ARRAY = #array\n";
}
test($test_scalar, #test_array);
system 'pause';
This will get you the same output.
You can also get rid of the $# altogether if you would like it really isn't necessary.
Why my #elem is empty ?
Your #elem is not empty, it has exactly two elements. First is value of $addr and second is size/number of elements in #curfile array. This is due $$ prototype definition which requires two scalars, so scalar #curfile is passed as second parameter.
How could I get back the array without loosing everything ?
Since you're not using prototype advantages, just omit prototype part,
sub send_file {
my ($addr, #elem) = #_;
...
}

Bash array of functions

I'm trying to create an array of functions in order to iterate through each function in order.
declare -a FUNCTION
FUNCTION[1]="FUNCTION.A"
FUNCTION[2]="FUNCTION.B"
FUNCTION[3]="FUNCTION.C"
for i in "${!FUNCTION[#]}"; do
${FUNCTION[$i]};
done
This just prints out FUNCTION.A and says command not found. I need it to run the function. Suggestions?
Works fine for me.
declare -a FUNCTION
FUNCTION[1]="FUNCTION.A"
FUNCTION[2]="FUNCTION.B"
FUNCTION[3]="FUNCTION.C"
#Define one of the functions
FUNCTION.A() { echo "Inside of FUNCTION.A"; }
$ for i in "${!FUNCTION[#]}"; do ${FUNCTION[$i]}; done
OUTPUT:
Inside of FUNCTION.A
FUNCTION.B: command not found
FUNCTION.C: command not found
Another way that I think looks a lot better
funcs_to_test=( voltage_force_landing voltage_warn_critical )
for testP in "${funcs_to_test[#]}"
do
$testP
done
And make sure to have written your functions above where you call this code
It is possible to define functions from names kept in an array and then call these functions after their definition:
#!/bin/sh
declare -a functions=( a b c )
for f in ${functions[#]}; do
eval "$f() {
echo "Hello from $f"
# ...
}"
$f
done
Alternatively:
#!/bin/sh
declare -a functions=( a b c )
a() { echo "Hello from $FUNCNAME"; }
b() { echo "Hello from $FUNCNAME"; }
c() { echo "Hello from $FUNCNAME"; }
for f in ${functions[#]}; do
$f
done
I'm a moron........ The function must apparently be above where its being called. Kinda annoying. I wish all the functions could reside at the bottom.
You can also declare the function like this
FUNCTION=(FUNCTION.A FUNCTION.B FUNCTION.C)
And then iterate through it like this:
for i in "${!FUNCTION[#]}"; do
${FUNCTION[i]}
This should work. If you just call "$i" it will only print the functions name from the array.
To avoid that little nuisance, just put the body of the script into yet another function. (I usually call it "app_main", because "main" is the name of the script's function as far as bash is concerned.)
#!/usr/bin/env bash # more portable
first() { echo "${FUNCNAME[0]}: $#" ; }
second() { echo "${FUNCNAME[0]}: $#" ; }
app_main() {
first "hello"
second "goodbye" 17 3.14159
}
app_main

Resources