• Publicidad

Problema de función o subrutina recursiva

¿Ya sabes lo que es una referencia? Has progresado, el nível básico es cosa del pasado y ahora estás listo para el siguiente nivel.

Problema de función o subrutina recursiva

Notapor jero2528 » 2015-12-11 16:39 @735

Saludos, Perleros.

Requiero realizar un proceso que se repite cierta cantidad de veces para lo cual realizando la codificación llegué a decidirme por una función recursiva. El problema es que al entrar la segunda vez a la función la misma no recibe los parámetros. ¿Me podrían ayudar a entender qué sucede o de qué otra forma lo podría hacer?

Inicialmente se le envía lo siguiente a la función:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if($#port2Dev > 0 && $#toIpDev > 0){
  2.         @port2Dev = grep { /\S/ } @port2Dev;
  3.         @toIpDev = grep { /\S/ } @toIpDev;
  4.         print "Elements (@port2Dev ) - (@toIpDev)\n\n\n";
  5.         &getIpInterface(\@port2Dev,\@toIpDev,10);
  6. }
  7.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


y de la siguiente manera la función recibe los parámetros, cabe aclarar que lo anterior está fuera de la función y su ejecución es correcta:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub getIpInterface {
  2.         print "Estoy en getIpInterface\n\n";
  3.         ($port2Dev,$toIpDev,$algo)=@_;
  4.        
  5.         @secPortDev="";
  6.         @secToIpDev="";
  7.  
  8.         print "entre a la función: (@$port2Dev, @$toIpDev) $algo\n\n";
  9.         print "tamaño: ($#$port2Dev, $#$toIpDev)\n\n";
  10.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Me genera la siguiente salida:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. Estoy en getIpInterface
  2.  
  3. entre a la función: (ge-2/0/0 Gi1/0/1, 10.0.120.129 190.60.229.25) 10
  4.  
  5. tamaño: (1, 1)
  6.  
  7.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4



Luego en el interior de la función realizo lo siguiente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if($#secPortDev > 0 && $#secToIpDev > 0){
  2.         @secPortDev = grep { /\S/ } @secPortDev;
  3.         @secToIpDev = grep { /\S/ } @secToIpDev;
  4.         print "New elements (@secPortDev) - (@secToIpDev)\n\n\n";
  5.         &getIpInterface(\@secPortDev,\@secToIpDev, 2222);
  6. }
  7.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4



Para lo cual la ejecución me genera la siguiente salida:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. New elements (ge-1/0/18 Gi0/1) - (172.17.229.8 190.60.229.30)
  2.  
  3.  
  4. Estoy en getIpInterface
  5.  
  6. entre a la función: (, ) 2222
  7.  
  8. tamaño: (0, 0)
  9.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Evidentemente los arreglos creados dentro de la función contienen información y no sé lo que sucede al entrar de nuevo a la función porque no captura esos arreglos :(.

Agradezco la ayuda o asesoría que me puedan prestar :)
Saludos,

Jero2528
Avatar de Usuario
jero2528
Perlero nuevo
Perlero nuevo
 
Mensajes: 50
Registrado: 2014-05-14 15:43 @697
Ubicación: Bogota, Colombia

Publicidad

Re: Problema de función o subrutina recursiva

Notapor explorer » 2015-12-11 17:15 @760

El problema es que la función recursiva usa variables globales, y en la siguiente llamada, son modificadas, por lo que al regresar la función, se las encuentra cambiadas o borradas.

Es lo que se llama "efectos colaterales" de las funciones.

Para que sea auténticamente recursiva deberías usar variables locales para los cálculos, y el trasiego de información entre llamadas usando argumentos y parámetros, también en variables locales.

En tu caso, en las líneas 5 y 6 borras los contenidos de los array principales, con lo que al regresar a la llamada anterior siguen vacíos.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problema de función o subrutina recursiva

Notapor jero2528 » 2015-12-14 08:39 @402

explorer: muchas gracias como siempre por tu atención.

Siento la necesidad de compartir el código completo para entender mejor lo que me indicas:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $vlanId="1147";
  2. my $contador=0;
  3. my $pos=0;
  4.  
  5. ######################################################################################
  6. ## Se Consultan las Vlan en los equipos del anillo para encontrar el principal
  7. ######################################################################################
  8. $query10G="select n.NodeID, n.IP_Address, n.Caption, n.Vendor from Nodes n where n.Propiedad='10G'";
  9. $r_query10G = $dbh01->selectall_arrayref("$query10G");
  10. foreach $row_r_query10G (@$r_query10G) {
  11.         if($r_query10G->[$contador]->[0]==1675){
  12.                 $pos=$contador;
  13.                 #print "my pos: $pos\t$r_query10G->[$contador]->[0]\n\n";
  14.                 my $ref_to_element = \$r_query10G[$pos];
  15.                 push (@$r_query10G, splice(@$r_query10G, $pos, 1));
  16.         }
  17.         $contador++;
  18. }
  19. foreach $row_r_query10G (@$r_query10G) {
  20.         ($NodeId,$IpAddress,$Caption,$Manufacturer) = @$row_r_query10G;
  21.          #print "Contador= $contador\n";
  22.          #print Dumper(@$r_query10G)."\n\n";
  23.          #exit 0;
  24.         my @port2Dev="";
  25.         my @toIpDev="";
  26.         my @portServDev="";
  27.         my $SID="";
  28.         my @portsDev=();
  29.         #print "arranque\n($NodeId,$IpAddress,$Caption,$Manufacturer)\n\n";
  30.         #####################################################################################
  31.         # Si se trata de un equipo Juniper, se procede de cierta forma para la eliminacion
  32.         #####################################################################################
  33.         if ($Manufacturer=~/Juniper/isg) {
  34.                 @conn1 = conectar_telnet($IpAddress,$userbackupsdefault,$passbackupsdefault);
  35.                 print "Conectado a $IpAddress\n";
  36.                 if ($conn1[0]) {
  37.                         $mensajeerror.="Equipo=$Caption, IP=$IpAddress, Descripcion=$conn1[0]\n<br>";
  38.                         $conteoerrores++;
  39.                 } else {
  40.                         my $line="";
  41.                         if($NodeId!=1675){
  42.                                 @out=$conn1[1]->cmd(String => "show vlans vlan$vlanId\n", Timeout => 10);
  43.                                 foreach $line (@out) {
  44.                                         #print "$line\n";
  45.                                         if ($line=~/\s+(.+)\.\d+\*\,\s?(.+)\.\d+\*\,\s?(.+)\.\d+\*/is){
  46.                                                 push(@portsDev, $1);
  47.                                                 print "$line\n--> $1, $2, $3\n\n";
  48.                                         }
  49.                                 }
  50.                         }else{
  51.                                 @out=$conn1[1]->cmd(String => "show ethernet-switching table vlan $vlanId\n", Timeout => 10);
  52.                                 foreach $line (@out) {
  53.                                         #print "$line\n";
  54.                                         if ($line=~/Learn.+0\s(.+)\.0\s?/i){
  55.                                                 push(@portsDev, $1);
  56.                                                 print "$line\n--> $1\n\n";
  57.                                         }
  58.                                 }
  59.                         }
  60.                         $line="";
  61.                        
  62.                         if($#portsDev > 0){
  63.                                 @portsDev = grep { /\S/ } @portsDev;
  64.                                 print "entro al if ya que el array es de tamano \@ports=$#portsDev\n\n";
  65.                                 foreach $port (@portsDev){
  66.                                         print "puerto: $port\n";
  67.                                         @out=$conn1[1]->cmd(String => "show interfaces descriptions $port\n", Timeout => 10);
  68.                                         foreach $line (@out){
  69.                                                 if($line=~/.*\#\-.*\[(.+?)\].+?\-(?:\s+)?((?:\d+\.){3}\d+)/is){
  70.                                                         push(@port2Dev,$1);
  71.                                                         push(@toIpDev,$2);
  72.                                                         print "$line\n\n(@port2Dev, @toIpDev)\n\n";
  73.                                                         #print Dumper(@port2Dev, @toIpDev);
  74.                                                 }
  75.                                         }
  76.                                 }
  77.                         }
  78.                         @out=$conn1[1]->cmd("exit\n");
  79.                 }
  80.                 cerrar_telnet($conn1[1]);
  81.                
  82.                 if($#port2Dev > 0 && $#toIpDev > 0){
  83.                         @port2Dev = grep { /\S/ } @port2Dev;
  84.                         @toIpDev = grep { /\S/ } @toIpDev;
  85.                         print "Elements (@port2Dev ) - (@toIpDev)\n\n\n";
  86.                         &getIpInterface(\@port2Dev,\@toIpDev,10);
  87.                 }
  88.         }
  89.         #Validar si el Servicio $SID es Igual al que se reporta en el router.
  90. }
  91.  
  92.  
  93. sub getIpInterface {
  94.         print "Estoy en getIpInterface\n\n";
  95.         ($port2Dev,$toIpDev,$algo)=@_;
  96.        
  97.         @secPortDev="";
  98.         @secToIpDev="";
  99.  
  100.         print "entre a la funcion: (@$port2Dev, @$toIpDev) $algo\n\n";
  101.         print "tamanio: ($#$port2Dev, $#$toIpDev)\n\n";
  102.         # exit 0;
  103.         if($#$port2Dev > 0 && $#$toIpDev > 0){
  104.                 $contador=0;           
  105.                 print "existen: port2Dev (@$port2Dev) y toIpDev (@$toIpDev)\n\n";
  106.                 print Dumper(@$port2Dev)."\n"; Dumper(@$toIpDev)."\n";
  107.                 foreach $toIp (@$toIpDev){
  108.                         $queryAccess="select n.NodeID, n.IP_Address, n.Caption, n.Vendor from Nodes n WITH (NOLOCK) where n.Ip_Address = '$toIp'";
  109.                         print "QueryAccess: $queryAccess\n";
  110.                         $r_queryAccess = $dbh01->selectall_arrayref("$queryAccess");
  111.                         foreach $row_r_queryAccess (@$r_queryAccess) {
  112.                                 ($NodeId,$IpAddress,$Caption,$Manufacturer) = @$row_r_queryAccess;
  113.                                 #print "arranque\n($NodeId,$IpAddress,$Caption,$Manufacturer)\n\n";
  114.                                 #####################################################################################
  115.                                 # Si se trata de un equipo Juniper, se procede de cierta forma para la eliminacion
  116.                                 #####################################################################################
  117.                                 if ($Manufacturer=~/Juniper/is) {
  118.                                         @conn1 = conectar_telnet($toIp,$userbackupsdefault,$passbackupsdefault);
  119.                                         if ($conn1[0]) {
  120.                                                 $mensajeerror.="IP=$toIp, Descripcion=$conn1[0]\n<br>";
  121.                                                 $conteoerrores++;
  122.                                         } else {
  123.                                                 @out=$conn1[1]->cmd(String => "show interfaces descriptions $$port2Dev[$contador]\n", Timeout => 10);
  124.                                                 foreach my $line (@out){
  125.                                                         print "Juniper: $line\n";
  126.                                                         # if($line=~/.*\#\-.*\[(.+?)\].+?\-(?:\s+)?((?:\d+\.){3}\d+)/is){
  127.                                                                 # push(@port2Dev,$1);
  128.                                                                 # push(@toIpDev,$2);
  129.                                                                 # print "Added: (@port2Dev, @toIpDev)\n\n";
  130.                                                         # }else{
  131.                                                                 # #Indicar Logica para ver descripcion de interfaz de Servicio
  132.                                                         # }
  133.                                                 }
  134.                                                 @out=$conn1[1]->cmd("exit\n")
  135.                                         }
  136.                                         cerrar_telnet($conn1[1]);
  137.                                 }elsif($Manufacturer=~/Cisco/is){
  138.                                         @conn1 = conectar_telnet_cisco($toIp,$userbackupsdefault,$passbackupsdefault);
  139.                                         if ($conn1[0]) {
  140.                                                 $mensajeerror.="IP=$toIp, Descripcion=$conn1[0]\n<br>";
  141.                                                 $conteoerrores++;
  142.                                         } else {
  143.                                                 @out=$conn1[1]->cmd(String => "terminal length 0");
  144.                                                 @out=$conn1[1]->cmd(String => "show vlan id $vlanId\n", Timeout => 10);
  145.                                                 foreach my $line (@out){
  146.                                                         if($line=~/.+active\s+(.+?)\,\s?(.+)/i){
  147.                                                                 push(@portServDev,$1);
  148.                                                                 push(@portServDev,$2);                                                                 
  149.                                                                 print "Cisco: $line\nPuerto servicio: $1,$2\n\n";
  150.                                                         }
  151.                                                 }
  152.                                                 if($#portServDev>0){
  153.                                                         @portServDev = grep { /\S/ } @portServDev;
  154.                                                         foreach my $portServ (@portServDev){
  155.                                                                 @out=$conn1[1]->cmd(String => "show interfaces $portServ | i Description\n", Timeout => 10);
  156.                                                                 foreach my $line (@out){
  157.                                                                         if ($line=~/(?:\s+)?description\:?\s?(\d+)\s\#/i){
  158.                                                                                 $SID=$1;
  159.                                                                                 print "$line\n\n-*-*-*-*-*-\tServicio: $SID\n";                                                                        
  160.                                                                         }elsif($line=~/.*\#\-.*\[(.+?)\].+?\-(?:\s+)?((?:\d+\.){3}\d+)/is){                                                                                    
  161.                                                                                 push(@secPortDev,$1);
  162.                                                                                 push(@secToIpDev,$2);
  163.                                                                                 print "2. $line\n\n(@secPortDev), (@secToIpDev)\n\n";
  164.                                                                         }
  165.                                                                 }
  166.                                                         }
  167.                                                 }
  168.                                                 @out=$conn1[1]->cmd("exit\n");
  169.                                         }
  170.                                         cerrar_telnet_cisco($conn1[1]);
  171.                                        
  172.                                         if($#secPortDev > 0 && $#secToIpDev > 0){
  173.                                                 @secPortDev = grep { /\S/ } @secPortDev;
  174.                                                 @secToIpDev = grep { /\S/ } @secToIpDev;
  175.                                                 print "New elements (@secPortDev) - (@secToIpDev)\n\n\n";
  176.                                                 &getIpInterface(\@secPortDev,\@secToIpDev, 2222);
  177.                                         }                                      
  178.                                 }
  179.                         }
  180.                         $contador++;
  181.                 }
  182.         }      
  183. }
  184.  
Coloreado en 0.005 segundos, usando GeSHi 1.0.8.4

Como puedes ver yo lo inicializo de acuerdo a una condición que si se se cumple hace que se vuelva a ejecutar la función.

Gracias por la ayuda :)
Saludos,

Jero2528
Avatar de Usuario
jero2528
Perlero nuevo
Perlero nuevo
 
Mensajes: 50
Registrado: 2014-05-14 15:43 @697
Ubicación: Bogota, Colombia

Re: Problema de función o subrutina recursiva

Notapor explorer » 2015-12-15 04:24 @225

Yo creo que pasa lo que te conté antes:

al llegar a la línea 176, llamas a la función pasando como argumentos \@secPortDev, \@secToIpDev, que son referencias a esos dos array, suponemos que para procesar sus contenidos, pero... de las primeras cosas que hace la propia función, en las líneas 97 y 98 es la de borrar sus contenidos, por lo que nos encontramos que $port2Dev, $toIpDev referencian a arrays vacíos.

La solución pasa por no usar variables globales, o modificar las variables globales sabiendo que van a afectar a ejecuciones posteriores/anteriores de la subrutina.

Por ejemplo, si acordamos que le pasamos a la función un par de listas de elementos, lo que podemos hacer es crear un par de arrays nuevos antes de la llamada, y se las pasamos a la función:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my @new_secPortDev = @secPortDev;
  2. my @new_secToIpDev = @secToIpDev;
  3. getIpInterface(\@new_secPortDev,\@new_secToIpDev, 2222);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Así no quedarán afectados con la modificación de los array globales.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Problema de función o subrutina recursiva

Notapor jero2528 » 2015-12-15 09:18 @429

explorer,

Mil gracias, ¡enhorabuena! Ha funcionado el script con lo que me has indicado, y ya me queda más claro por qué sucedía lo que generó que se creara este hilo.

:) :mrgreen:


Gracias.
Saludos,

Jero2528
Avatar de Usuario
jero2528
Perlero nuevo
Perlero nuevo
 
Mensajes: 50
Registrado: 2014-05-14 15:43 @697
Ubicación: Bogota, Colombia


Volver a Intermedio

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado