• Publicidad

Crear archivo con espacio en blanco y variables en el nombre

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

Crear archivo con espacio en blanco y variables en el nombre

Notapor JoshZeta » 2015-09-22 16:51 @743

Buenas, estimados perleros :D Tengo un gran dilema que me aqueja desde hace unos días :? (seguro para ustedes es algo muy fácil :lol: ).

Dentro de mi código tengo la necesidad de crear un archivo que contenga en su nombre espacios en blanco y se cree en función a variables. Para que me entiendan, mejor un ejemplo :
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $variable1 = "nombre";
  2. my $variable2 = "archivo";
  3. my $nombre="$variable1\ $variable2.csv";
  4.  
  5. system ("touch $nombre");
Coloreado en 0.005 segundos, usando GeSHi 1.0.8.4

Como pueden apreciar, para crear el archivo ejecuto un comando externo (Linux) con la función system(). Y para escapar del espacio uso el carácter "\".

Si escribo el nombre manualmente en Linux:
Sintáxis: [ Descargar ] [ Ocultar ]
Using bash Syntax Highlighting
  1. touch nombre\ archivo.csv
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4

Crea sin ningún problema el archivo "nombre archivo.csv", pero cuando ejecuto el script solo crea el archivo con la última variable "archivo.csv" y menciona como error que no existe el fichero "nombre".

¡OJO que solo es un ejemplo! El valor de las variables, el valor real, es el producto de diferentes funciones, solo pongo esos valores a modo didáctico.

Muchas gracias por la atención prestada. :)
JoshZeta
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2015-08-20 11:40 @527

Publicidad

Re: Crear archivo con espacio en blanco y variables en el no

Notapor explorer » 2015-09-22 17:41 @778

Cuando pones un '\' entre comillas dobles, se produce una "interpolación" de las variables y de los caracteres "escapados" por el carácter '\'.

Entonces,
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $variable1 = "nombre";
  2. my $variable2 = "archivo";
  3. my $nombre    = "$variable1\ $variable2.csv";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

hace que $nombre sea 'nombre archivo'. Y cuando se lo pasamos a system(), como estamos usando otras comillas dobles, se produce otra interpolación, por lo que

system ("touch $nombre");

se transforma en

system ('touch nombre archivo');

Y esa es la razón de que se creen dos archivos, en lugar de uno solo.

Solución clásica
Como nuestra cadena de caracteres va a sufrir dos interpolaciones, necesitamos "retrasar" el efecto del "escapado" de la barra diagonal inversa hasta el momento de la segunda interpolación:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $variable1 = "nombre";
  2. my $variable2 = "archivo";
  3. my $nombre    = "$variable1\\ $variable2.csv";
  4. system("touch $nombre");     # touch nombre\ archivo.csv
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

La barra diagonal pasa al shell, y éste se encargará de escapar el espacio en blanco, por lo que se creará un solo archivo, con el espacio en medio.

Solución Perl 1
Si sospechamos que tenemos "caracteres peligrosos" a la hora de crear archivos, podemos pedirle a Perl que los "escape" por nosotros:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $variable1 = "nombre";
  2. my $variable2 = "archivo";
  3. my $nombre    = "\Q$variable1 $variable2.csv\E";
  4. system("touch $nombre"); # touch nombre\ archivo.csv
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

que es lo mismo que usar la función quotemeta():
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $variable1 = "nombre";
  2. my $variable2 = "archivo";
  3. my $nombre    = quotemeta "$variable1 $variable2.csv";
  4. system("touch $nombre"); # touch nombre\ archivo.csv
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Las opciones de escapado "\Q...\E" están descritas en perldoc perlop en la sección Quote and Quote-like Operators, y de forma más específica en perldoc -f quotemeta.

Solución Perl 2
Podemos también... evitar la segunda interpolación, cambiando la forma de llamar a system():
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $variable1 = "nombre";
  2. my $variable2 = "archivo";
  3. my $nombre    = "$variable1 $variable2.csv";
  4. system('touch', $nombre); # touch "nombre archivo.csv"
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

De hecho, el problema está en llamar a system() con solo un argumento. Lo que dice el manual en perldoc -f system es:
system LISTA
system PROGRAMA LISTA

Hace exactamente lo mismo que "exec LISTA", excepto que se hace
primero un fork y el proceso padre espera a que el proceso hijo
termine. Tenga en cuenta que el tratamiento de los argumentos varía en
función del número de argumentos. Si hay más de un argumento en LISTA,
o si la lista es un array con más de un valor, se inicia el programa
indicado en el primer elemento de la lista, con los argumentos
indicados por el resto de la lista. Si sólo hay un argumento escalar,
se comprueba si el argumento tiene metacaracteres, y si hay alguno, el
argumento entero es pasado al shell de comandos para que sea
interpretado (suele ser "/bin/sh -c" en plataformas Unix, pero varía
en otras plataformas). Si no hay metacaracteres shell en el argumento,
es dividido en palabras
y pasadas directamente a "execvp", que es más
eficiente.

Así que... si solo pasamos un argumento, se divide en palabras (por los espacios en blanco), y pasadas a la función del sistema para que lo ejecute. De ahí viene el problema de tener que escapar cuando usas las comillas dobles.

La solución, como has visto, es la de llamar a system() con más de un argumento.

¿Cuál elegir? La preferida es la última, ya que deja el código más limpio, y Perl no tiene que hacer ninguna operación de "escapado" previo.

P.D.: En vez de llamar a un comando externo 'touch', es preferible usar un open() de Perl. Así no dependes de la existencia o no de un comando externo ni le pides al sistema que arranque un proceso nuevo.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Crear archivo con espacio en blanco y variables en el no

Notapor JoshZeta » 2015-09-24 13:18 @596

Hola, explorer, gracias por responder :D

Intenté con todos los métodos mencionados y pasa algo curioso. Como mencioné en un principio se creaba el archivo pero solo con la segunda variable "archivo.csv" y salía el error de carpeta no encontrada con la primera variable "nombre". Pero ahora no se crea ningún archivo y el error hace referencia al nombre completo "nombre archivo.csv" :?

Entiendo que ahora el valor de la variable sí está pasando completo pero no entiendo por qué no crea el archivo y sale el error.

PD: antes de usar system() usaba open(), pero con open() simplemente no pasaba nada (ni creaba el archivo ni salía error), por eso opté usar system().
JoshZeta
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2015-08-20 11:40 @527

Re: Crear archivo con espacio en blanco y variables en el no

Notapor explorer » 2015-09-25 18:45 @823

Si estás ejecutando un open(), y estás especificando el modo en escritura '>', debe, necesariamente, pasar una de estas cosas:
  • si el archivo no existe en el directorio actual, se crea un nuevo archivo con tamaño de 0 bytes:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using bash Syntax Highlighting
    1. > perl -E 'open F, ">", "nombre archivo.csv" or die "ERROR: $!\n"; close F'
    2. > ll "nombre archivo.csv"
    3. -rw-r--r-- 1 explorer users 0 sep 26 01:28 nombre archivo.csv
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
  • si el archivo ya existía, el archivo se pone a 0 bytes:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using bash Syntax Highlighting
    1. > ll "nombre archivo.csv"
    2. -rw-r--r-- 1 explorer users 300 sep 26 01:30 nombre archivo.csv
    3. > perl -E 'open F, ">", "nombre archivo.csv" or die "ERROR: $!\n"; close F'
    4. > ll "nombre archivo.csv"
    5. -rw-r--r-- 1 explorer users 0 sep 26 01:31 nombre archivo.csv
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
  • si en el directorio donde pretendemos crear el archivo no tenemos permiso de escritura, no se creará el archivo y saldrá un mensaje de error:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using bash Syntax Highlighting
    1. > chmod u-w .           # quitamos permiso de escritura a nosotros mismos, en todo el directorio
    2. > perl -E 'open F, ">", "nombre archivo.csv" or die "ERROR: $!\n"; close F'
    3. ERROR: Permission denied
    4. > chmod u+w .           # recuperamos los permisos, para dejarlo todo como estaba
    Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
  • si no hay espacio en disco, o el sistema de archivos está en solo lectura, o si el dispositivo tiene un error de hardware, saldrá otro mensaje de error distinto
Te pido que agregues comandos die() como el que te pongo, para que saquen el valor de la variable especial $!, que contiene el texto del último mensaje de error producido.

Si esto no funciona, habrá que pensar que estás usando un código más complicado del que nos muestras. En ese caso, te pido que intentes escribir el programa de Perl más pequeño que puedas, que reproduzca el error, para que lo probemos nosotros.

Por ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use autodie;            # este módulo ahorra tener que poner die() en los open, close, print y mkdir
  3.  
  4. my $carpeta = 'carpeta_prueba';
  5.  
  6. mkdir $carpeta;
  7.  
  8. my $variable1 = "nombre";
  9. my $variable2 = "archivo";
  10. my $nombre    = "$variable1 $variable2.csv";
  11.  
  12. open my $FICHERO, '>', "$carpeta/$nombre";
  13. close   $FICHERO;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Crear archivo con espacio en blanco y variables en el no

Notapor JoshZeta » 2015-09-28 14:45 @656

Usé el open() y el error que sale es el siguiente: No such file or directoryn at ./M3LNK2.pl, donde lo último es el nombre del script perl que ejecuto.

Este es el programa :
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use strict;
  3. use warnings ;
  4.  
  5.  
  6. my $fuen = "/home/osboxes/Desktop/N2000/M3LNK carga/M3LNK.csv";
  7. open my $FF,'<',$fuen;
  8. my $regi = <$FF>;
  9. chomp $regi;
  10. my $regi2 = <$FF>;
  11. my @nom= split ',',$regi2;
  12. close $FF;
  13. my $n1=substr($nom[4],0,10);
  14. my $n2=substr($nom[4],11,8);
  15. my $n3="$n1\ $n2";
  16. my $n4=substr($nom[0],0,10);
  17. my $n5=substr($nom[0],11,8);
  18. my $n6="$n4\\ $n5.csv";
  19.  
  20. my $name = "PCT_CARGA_BCGI_$n3"."_$n6.csv";
  21.  
  22. #-----------------------------
  23.  
  24.  
  25. #system ("touch $name");
  26.  
  27. #open my $NN,'>',$name or die "ERROR: $!n";
  28. #close $NN
  29.  
  30. #---------------------------
  31. #my $pru = "salida.csv" ;
  32. open my $FD,'>',$name;
  33. chmod 0777, $pru ;
  34. my $linea =  "collectionEndTime,deviceID,PCT";
  35. print $FD "$linea\n";
  36. close $FD;
  37. #-----------------------------------------------------------------
  38. my $nm = "/home/osboxes/Desktop/N2000/M3LNK carga/M3LNK.csv";
  39. #my $sal = "salida.csv";
  40. open my $FORMAT_F,'<',$nm;
  41. open my $FORMAT_D,'>>',$name;
  42. chmod 0777, $name;
  43. my $i = 0 ;
  44. while (my $registro = <$FORMAT_F>){
  45. next if $. == 1 ;
  46. chomp $registro;
  47. my @campo = split ',',$registro;
  48. $campo[5] = ((($campo[2] + $campo[3])/3600)/5000)*100;
  49. my $archivo = join ',',@campo[0,1,5] ;
  50. print $FORMAT_D "$archivo\n";
  51. $i++;
  52. }
  53. close $FORMAT_F;
  54. close $name;
  55.  
  56. rename "/home/osboxes/Desktop/N2000/M3LNK carga/$sal","/home/osboxes/Desktop/N2000/M3LNK carga/CN2/$name";
  57.  
  58. print "\n\t Operación realizada con exito : $i registros. \n";
  59.  
  60.  
  61.  
  62.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Lo que el programa hace es en función a un archivo, crea otro nuevo, operando el valor de unas columnas y le pone el nombre al archivo en base al valor procesado de una fila.
JoshZeta
Perlero nuevo
Perlero nuevo
 
Mensajes: 13
Registrado: 2015-08-20 11:40 @527

Re: Crear archivo con espacio en blanco y variables en el no

Notapor explorer » 2015-10-03 05:53 @286

Pero el mensaje de error debería indicar el número de línea donde ha ocurrido.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Crear archivo con espacio en blanco y variables en el no

Notapor josemanu87 » 2015-10-20 08:10 @382

Muchas gracias por la respuesta, muchas gracias
josemanu87
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2015-10-20 08:03 @377


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 3 invitados