• Publicidad

Impresión recursiva de directorios

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Impresión recursiva de directorios

Notapor chanozg » 2012-02-04 15:09 @673

Estoy haciendo un script en Perl y tengo un problema en una de las funciones.

Este es el enunciado de la función:

mostrar_directorio [directorio]
Recorre recursivamente el árbol de directorio partiendo desde el directorio pasado como argumento.
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
(ayuda/salir)? mostrar_directorio ...
 etc (Directorio)
  group
  passwd
 script (Directorio)
  config.txt
  historico.txt
  minishell.pl
  minishell..pl~
  ....
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Hasta ahí todo sin problemas pero ahora debo añadir...

Lo único que se debe de modificar es la salida. Esta estará claramente sangrada y se intentará representar lo más parecido a un árbol gráfico. Para ello se emplearán los caracteres: ‘|’, ‘\’ y ‘-‘.

Veámoslo en un ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
(ayuda/salir)? mostrar_directorio ..
.. (Directorio de partida)
|-script(Directorio)
| |-config.txt
| |-config2.txt
| |-config3.txt
| |-minishell.pl
| |-pruebas.bash
| |-pruebas.txt
| |-pruebas2.txt
| |-pruebas3.txt
| \-historico.txt
|-home2(Directorio)
| |-alum3(Directorio)
| |-alum2(Directorio)
| \-alum1(Directorio)
|   |-f1
|   |-f2
|   \-f3
|-home(Directorio)
| |-sin_x(Directorio) >>>> ERROR: A <../home/sin_x> le falta el permiso de busqueda.
| \-sin_r(Directorio) >>>> ERROR: A <../home/sin_r> le falta el permiso de lectura.
\-etc(Directorio)
  |-group
  |-group2
|-passwd
  \-passwd2
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Esta es la función que ha sacado por ahora:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub mostrar_directorio {
  2.     my ( $d, $sangrado ) = @_;
  3.     my (@subd);
  4.  
  5.     #comprobaciones de permisos y ficheros
  6.  
  7.     if ( !( -e "$d" ) ) {
  8.         print(">>>> ERROR: No existe <$d>\n");
  9.         return;
  10.     }
  11.  
  12.     if ( !( -r "$d" ) ) {              #lectura
  13.         print ">>>> ERROR: A <$d> le falta el permiso de lectura.\n";
  14.     }
  15.  
  16.     if ( !( -w "$d" ) ) {              #modificación
  17.         print ">>>> ERROR: A <$d> le falta el permiso de modificación.\n";
  18.     }
  19.  
  20.     if ( !( -x "$d" ) ) {              #búsqueda
  21.         print ">>>> ERROR: A <$d> le falta el permiso de búsqueda.";
  22.     }
  23.  
  24.     if ( !opendir( DIR, "$d" ) ) {     #comprobar apertura
  25.         return;
  26.     }
  27.  
  28.     @subd = readdir(DIR);
  29.     $sangrado .= ' ';
  30.     print("\n");
  31.     foreach ( (@subd) ) {
  32.         if (/^\.{1,2}$/) { next; }     #comprobar no es directorio trabajo o anterior
  33.  
  34.         if ( -d "$d/$_" )              #comprobar que sea directorio
  35.         {
  36.             print("$sangrado|-$_ (Directorio)");
  37.             mostrar_directorio( "$d/$_", $sangrado );    #llamada recursiva
  38.         }
  39.         else {
  40.             print " |$sangrado|-$_\n"; #no es un directorio, imprimimos
  41.         }
  42.         close(DIR);                    #cerramos el directorio
  43.     }
  44.  
  45.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Así llevo la función hasta ahora; lo único que me falta es saber cómo poner la barra "\" que no tengo ni idea.

Espero que alguien me pueda ayudar.
Última edición por explorer el 2012-02-04 15:35 @691, editado 2 veces en total
Razón: Formateado de código con Perltidy y poner marcas Texto
chanozg
Perlero nuevo
Perlero nuevo
 
Mensajes: 11
Registrado: 2012-02-04 15:02 @668

Publicidad

Re: Impresión recursiva de directorios

Notapor explorer » 2012-02-04 15:34 @690

Bienvenido a los foros de Perl en español, chanozg.

La pista que tienes para colocar el '\' como último elemento del subdirectorio, es que es el último elemento de @subd, así que dentro del bucle puedes hacer un
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if ($_ eq $subd[-1]) {    # ¿Estamos con el último elemento?
  2.     ...;
  3. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
y si es así, cambiamos el '|' por un '\', y ya está.

P.D. Te sobran paréntesis en las líneas 7, 12, 16, 20 y 31.
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: Impresión recursiva de directorios

Notapor chanozg » 2012-02-04 15:54 @704

Estoy haciendo pruebas y no veo claro dónde debo meter ese if().

¿Iría entre la línea 36-37?
chanozg
Perlero nuevo
Perlero nuevo
 
Mensajes: 11
Registrado: 2012-02-04 15:02 @668

Re: Impresión recursiva de directorios

Notapor explorer » 2012-02-04 16:18 @720

Yo veo dos líneas en las que haces uso del '|'.

Entonces, lo primero que haría dentro del bucle (antes de la 34), es ver si se trata o no del último elemento de @subd. Según sea o no, pondré el valor de una variable llamada, por ejemplo, $delimitador, al valor '|' o al '\'. Y luego, siguen las mismas líneas que tienes ahora, pero cambiando la aparición del '|' por la variable $delimitador.

Así, las salidas son las mismas que antes, pero el delimitador cambia cuando se trata del último elemento.
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: Impresión recursiva de directorios

Notapor chanozg » 2012-02-04 16:43 @738

Lo primero, muchísimas gracias, que aún no te las había dado...

Me estoy acercando bastante.

Hasta aquí he llegado:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.  
  2. sub mostrar_directorio{
  3.     my($d, $sangrado)=@_;
  4.     my(@entradas);
  5.  
  6.  
  7.     #comprobaciones de permisos y ficheros
  8.  
  9.     if(!(-e "$d")){
  10.         print(">>>> ERROR: No existe <$d>\n");
  11.         return;
  12.     }
  13.     if (!(-r "$d")){ #lectura
  14.         print ">>>> ERROR: A <$d> le falta el permiso de lectura.\n";
  15.     }
  16.  
  17.     if (!(-w "$d")){ #modificación
  18.         print ">>>> ERROR: A <$d> le falta el permiso de modificación.\n";
  19.     }
  20.  
  21.     if (!(-x "$d")){ #búsqueda
  22.         print ">>>> ERROR: A <$d> le falta el permiso de búsqueda.";
  23.     }
  24.     if(!opendir(DIR, "$d")){ #comprobar apertura
  25.         return;
  26.     }
  27.  
  28.  
  29.  
  30.  
  31.     @entradas=readdir(DIR);
  32.     $sangrado .=' ';
  33.     print("\n");
  34.     foreach((@entradas))
  35.     {
  36.         if(/^\.{1,2}$/) {next;} #comprobar no es directorio trabajo o anterior
  37.  
  38.         if($_ eq $entradas[-1])
  39.         {
  40.         $delimitador='\-';
  41.         }
  42.         else
  43.         {
  44.         $delimitador='|-';
  45.         }
  46.  
  47.         if(-d "$d/$_") #comprobar que sea directorio
  48.         {
  49.              print("$sangrado.$delimitador.$_ (Directorio)");
  50.              mostrar_directorio("$d/$_", $sangrado); #llamada recursiva
  51.         }
  52.         else
  53.         {
  54.              print " |$sangrado.$delimitador.$_\n"; #no es un directorio, imprimimos
  55.         }
  56.      }
  57.      close (DIR); #cerramos el directorio
  58.  
  59. }
  60.  
  61.  
  62.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Sigo haciendo algo mal porque este es el resultado que obtengo:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
mostrar_directorio ..

 .|-.script (Directorio)
 |  .|-.historico2.txt
 |  .|-.enunciado_rubrica_v1.odt
 |  .|-.enunciado_rubrica_v1.pdf
 |  .|-.pruebas3.txt
 |  .|-.salida.txt
 |  .|-.config.txt
 |  .|-.pruebas.bash
 |  .|-.config3.txt
 |  .|-.pruebas.txt
 |  .|-.pruebas4.txt~
 |  .|-.minishellbueno.pl~
 |  .|-.historico.txt
 |  .|-.minishellbueno.pl
 |  .|-.minishell2.pl~
 |  .|-.salida.odt
 |  .|-.minishell.pl~
 |  .|-.pruebas2.txt
 |  .|-.pruebas4.txt
 |  .|-.salida.pdf
 |  .|-.config2.txt
 |  .|-.minishell.pl
 |  .|-.entradas.txt
 |  .\-.minishell2.pl
 .|-.etc (Directorio)
 |  .|-.group2
 |  .|-.passwd
 |  .|-.group
 |  .|-.passwd2
 .|-.home (Directorio)
  .|-.sin_r (Directorio)
  .|-.sin_x (Directorio)
 .|-.home2 (Directorio)
  .|-.alum3 (Directorio)
  .|-.alum2 (Directorio)
  .\-.alum1 (Directorio)
 |   .|-.f2
 |   .|-.f1
 |   .|-.f3
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


¿Qué estoy haciendo mal ahora?
chanozg
Perlero nuevo
Perlero nuevo
 
Mensajes: 11
Registrado: 2012-02-04 15:02 @668

Re: Impresión recursiva de directorios

Notapor explorer » 2012-02-04 20:10 @881

Lo primero, estás poniendo puntos '.' demás, en los print de las líneas 49 y 54. Quítalos.

Segundo, estás usando el mismo controlador (DIR) para todas las vueltas, y eso no me gusta nada. No afecta mucho porque haces la operación @entradas=readdir(DIR);, con la que lees todo el contenido del directorio, de golpe. Pero es mucho más seguro hacerlo así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if(!opendir(my $DIR, $d)){ # comprobar apertura
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     @entradas = readdir($DIR);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.      close ($DIR); # cerramos el directorio
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Tercero; algunos directorios ves que no acaban con '\'. Eso es porque en la línea 31 estás leyendo todo los archivos y directorios, incluidos los que excluyes en la línea 36. Y eso es lo que precisamente ocurre: resulta que en el subdirectorio etc/, las últimas entradas corresponden a esos directorios especiales. Al ser descartados por la línea 36, nunca se cumple la condición de la 38, por lo que no aparece el '\'.

La solución es filtrar los directorios especiales justo en el momento de leerles con readdir(): quita la 36 y la 31 la reescribes así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     @entradas = grep { !/^\.{1,2}$/ } readdir(DIR);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Hay otro detalle... me parece... y es que en la línea 32 sumas un espacio como espacio de sangrado, pero según el ejemplo de salida, quizás deberían ser dos, excepto... ¿el primer nivel?
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: Impresión recursiva de directorios

Notapor chanozg » 2012-02-04 23:09 @006

Ahora no

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub mostrar_directorio{
  2.     my($d, $sangrado)=@_;
  3.     my(@entradas);
  4.  
  5.  
  6.     #comprobaciones de permisos y ficheros
  7.  
  8.     if(!(-e "$d")){
  9.         print(">>>> ERROR: No existe <$d>\n");
  10.         return;
  11.     }
  12.     if (!(-r "$d")){ #lectura
  13.         print ">>>> ERROR: A <$d> le falta el permiso de lectura.\n";
  14.     }
  15.  
  16.     if (!(-w "$d")){ #modificacion
  17.         print ">>>> ERROR: A <$d> le falta el permiso de modificacion.\n";
  18.     }
  19.  
  20.     if (!(-x "$d")){ #busqueda
  21.         print ">>>> ERROR: A <$d> le falta el permiso de busqueda.";
  22.     }
  23.     if(!opendir(my $DIR, $d)){ #comprobar apertura
  24.         return;
  25.     }
  26.  
  27.  
  28.  
  29.  
  30.     @entradas = grep { !/^\.{1,2}$/ } readdir(DIR);
  31.     $sangrado .=' ';
  32.     print("\n");
  33.     foreach((@entradas))
  34.     {
  35.  
  36.         if($_ eq $entradas[-1])
  37.         {
  38.         $delimitador='\-';
  39.         }
  40.         else
  41.         {
  42.         $delimitador='|-';
  43.         }
  44.  
  45.         if(-d "$d/$_") #comprobar que sea directorio
  46.         {
  47.              print("$sangrado $delimitador $_  (Directorio)");
  48.              mostrar_directorio("$d/$_", $sangrado); #llamada recursiva
  49.         }
  50.         else
  51.         {
  52.              print " |$sangrado $delimitador $_\n"; #no es un directorio, imprimimos
  53.         }
  54.      }
  55.      close ($DIR); #cerramos el directorio
  56.  
  57. }
  58.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Ahora no obtengo resultado

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
2 : mostrar_directorio ..
readdir() attempted on invalid dirhandle DIR at minishell2.pl line 207, <> line 2.

Use of uninitialized value $DIR in ref-to-glob cast at minishell2.pl line 232, <> line 2.

3 : mostrar_directorio ../home
readdir() attempted on invalid dirhandle DIR at minishell2.pl line 207, <> line 3.

Use of uninitialized value $DIR in ref-to-glob cast at minishell2.pl line 232, <> line 3.
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


He probado a poner tambien el $ delante de DIR en la linea 30 pero tampoco obtengo resultado
chanozg
Perlero nuevo
Perlero nuevo
 
Mensajes: 11
Registrado: 2012-02-04 15:02 @668

Re: Impresión recursiva de directorios

Notapor explorer » 2012-02-05 06:09 @298

El error que sacas es, precisamente, de poner DIR, en lugar de $DIR.

Lo que pasa es que estás declarando $DIR dentro, y solo dentro, del if() de las líneas 23 a 25. No es conocido en el resto de líneas.

Coloca el my $DIR; en la línea 5, y en la línea 23, pon solamente if(!opendir($DIR, $d)){
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: Impresión recursiva de directorios

Notapor chanozg » 2012-02-05 08:11 @382

Aquí te dejo un ejemplo con lo que debería salirme

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
(ayuda/salir)? mostrar_directorio ..
.. (Directorio de partida)
|-script(Directorio)
| |-config.txt
| |-config2.txt
| |-config3.txt
| |-minishell.pl
| |-pruebas.bash
| |-pruebas.txt
| |-pruebas2.txt
| |-pruebas3.txt
| \-historico.txt
|-home2(Directorio)
| |-alum3(Directorio)
| |-alum2(Directorio)
| \-alum1(Directorio)
|   |-f1
|   |-f2
|   \-f3
|-home(Directorio)
| |-sin_x(Directorio) >>>> ERROR: A <../home/sin_x> le falta el permiso de busqueda.
| \-sin_r(Directorio) >>>> ERROR: A <../home/sin_r> le falta el permiso de lectura.
\-etc(Directorio)
  |-group
  |-group2
  |-passwd
  \-passwd2
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Doy por hecho que el orden no importa...

En mi resultado me sobran unas barras "|" que no veo la forma de que desaparezca.

Y no me aparecen eso errores que detecta que los archivos no tienen los permisos activados.

Aquí el código

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. sub mostrar_directorio{
  2.     my($d, $sangrado)=@_;
  3.     my(@entradas);
  4.  
  5.     my($DIR);
  6.     #comprobaciones de permisos y ficheros
  7.  
  8.     if(!(-e "$d")){
  9.         print(">>>> ERROR: No existe <$d>\n");
  10.         return;
  11.     }
  12.     if (!(-r "$d")){ #lectura
  13.         print ">>>> ERROR: A <$d> le falta el permiso de lectura.\n";
  14.     }
  15.  
  16.     if (!(-w "$d")){ #modificacion
  17.         print ">>>> ERROR: A <$d> le falta el permiso de modificacion.\n";
  18.     }
  19.  
  20.     if (!(-x "$d")){ #busqueda
  21.         print ">>>> ERROR: A <$d> le falta el permiso de busqueda.";
  22.     }
  23.     if(!opendir($DIR, $d)){ #comprobar apertura
  24.         return;
  25.     }
  26.  
  27.  
  28.  
  29.  
  30.     @entradas= grep { !/^\.{1,2}$/ } readdir($DIR);
  31.     $sangrado .=' ';
  32.     print("\n");
  33.     foreach((@entradas))
  34.     {
  35.        
  36.  
  37.         if($_ eq $entradas[-1])
  38.         {
  39.         $delimitador='\-';
  40.         }
  41.         else
  42.         {
  43.         $delimitador='|-';
  44.         }
  45.  
  46.         if(-d "$d/$_") #comprobar que sea directorio
  47.         {
  48.              print("$sangrado $delimitador $_  (Directorio)");
  49.              mostrar_directorio("$d/$_", $sangrado); #llamada recursiva
  50.         }
  51.         else
  52.         {
  53.              print "  |$sangrado $delimitador $_\n"; #no es un directorio, imprimimos
  54.         }
  55.      }
  56.      close ($DIR); #cerramos el directorio
  57.  
  58. }
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Y aquí mi resultado:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
2 : mostrar_directorio ..

  |- script  (Directorio)
  |   |- historico2.txt
  |   |- enunciado_rubrica_v1.odt
  |   |- enunciado_rubrica_v1.pdf
  |   |- pruebas3.txt
  |   |- salida.txt
  |   |- config.txt
  |   |- pruebas.bash
  |   |- config3.txt
  |   |- pruebas.txt
  |   |- pruebas4.txt~
  |   |- minishellbueno.pl~
  |   |- historico.txt
  |   |- minishell2.pl~
  |   |- salida.odt
  |   |- minishell.pl~
  |   |- pruebas2.txt
  |   |- pruebas4.txt
  |   |- salida.pdf
  |   |- config2.txt
  |   |- minishell.pl
  |   |- entradas.txt
  |   \- minishell2.pl
  |- etc  (Directorio)
  |   |- group2
  |   |- passwd
  |   |- group
  |   \- passwd2
  |- home  (Directorio)
   |- sin_r  (Directorio)
   \- sin_x  (Directorio)
  \- home2  (Directorio)
   |- alum3  (Directorio)
   |- alum2  (Directorio)
   \- alum1  (Directorio)
  |    |- f2
  |    |- f1
  |    \- f3
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Son estas 3 últimas barritas de la izquierda las que me sobran.
chanozg
Perlero nuevo
Perlero nuevo
 
Mensajes: 11
Registrado: 2012-02-04 15:02 @668

Re: Impresión recursiva de directorios

Notapor explorer » 2012-02-05 10:50 @493

Un compañero tuyo se adelantó aquí. En su primer mensaje aparece resuelto la forma de sacar el directorio, aunque no sigue la misma salida esperada que la que indicas tu. Y sospecho de que se puede simplificar un poco, aunque si tiene que ser exactamente la salida pedida, hay que tener en cuenta algún caso especial.

Y sobre el tema de los permisos que no aparecen en los directorios de pruebas, mira los últimos mensajes.
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

Siguiente

Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: Bing [Bot] y 36 invitados