Avatar billede kkrasmussen Nybegynder
05. september 2008 - 11:00 Der er 24 kommentarer og
3 løsninger

Multidimension array med PERL

Hej alle.
jeg vil gerne have hjælp til en simpel lille operation.
Jeg er igang med noget IDM og i den forbindelse modtager jeg i mit PERL script, nogle variabler.
Den ene er en streng som KUNNE se sådan ud:

my $tekst = "dette,er,en,test/hvorfor,er,det,det?";

Denne streng ønsker jeg at få delt op i et 2 dimensionelt array(eller som man kun kan i perl, i et array med flere arrays).

Nogenlunde sådan her:

[0 => "dette","er","en",""test][2 => "Hvorfor","er","det"det?,""]

Jeg har forsøgt dette:
** Kode starter **
my $teststring = "hello,world/how,are,u,2day?/I,am,fine";

my @tmpdns = split(',', $teststring);

my $num = scalar (@tmpdns);

for($i = 0; $i < $num; $i++)
{
  my @dns .= (@tmpdns($i(split('-', $teststring))));
}
** Kode slut **

Men det virker ikke.
Avatar billede Slettet bruger
05. september 2008 - 11:17 #1
Jeg anvender lige Data::Dumper for nemt at kunne printe datastrukturen.

Du skal jo splitte på '/' først, og derefter på ',', jeg ville gøre det således


#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my $tekst = "hello,world/how,are,u,2day?/I,am,fine";

my @break = split /\//, $tekst;
my @out = ();
for my $b (@break) {
  push @out, [ split /\,/, $b ];
}

print Dumper \@out;
exit;
Avatar billede kkrasmussen Nybegynder
05. september 2008 - 11:28 #2
Jeg bruger også Data::Dumper.

And well, tak for hjælpen. lige nøjagtig den løsning virkede perfekt. Tak for det.
Avatar billede Slettet bruger
05. september 2008 - 11:35 #3
Vi kan også lave en oneliner

@out = map { [ split /\,/, $_ ] } split /\//, $tekst;
Avatar billede kkrasmussen Nybegynder
05. september 2008 - 12:12 #4
Det er fint som du skrev før. Det virker som det skal.
Skriver du et svar jeg kan give point på?
Avatar billede Slettet bruger
05. september 2008 - 12:22 #5
har jeg allerede gjort to gange

fordelen ved onelineren er at vi ikke skal allokere en temp variabel (@break), ikke at det har den store betydning
Avatar billede kkrasmussen Nybegynder
05. september 2008 - 12:33 #6
Hm. Jeg kan bare ikke godkende dit svar... :S
Avatar billede Slettet bruger
05. september 2008 - 12:57 #7
Er der ikke abre en snak ved et af svarene? som der skal trykes på.
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 07:03 #8
Bortset fra det, så kan det alligevel ikke bruges. IDM driveren er meget striks mht syntaks. Jeg er lige nødt til at poste hele scriptet.

*********************************************************************************

#!/usr/bin/perl
#
# DESCRIPTION
#
#  This script implements the add command for the external Linux/UNIX
#  application.
#
#  The add command is an input command.  The IDM engine sends an add command
#  to the subscriber shim to request that the external application add an
#  entry.
#
#
# VARIABLES
#
#  SRC_DN
#    Specifies the distinguished name of the entry to add, in the name space
#    of eDirectory.  When the IDM engine sends the add command, the subscriber
#    should copy the SRC_DN attribute to the outgoing DEST_DN command.
#
#  SRC_ENTRY_ID
#    Specifies the entry ID of the entry that generated the add event.  It is
#    specified in the name space of eDirectory.  When the IDM engine sends
#    the add command, the subscriber should copy the SRC_ENTRY_ID attribute
#    to the outgoing DEST_ENTRY_ID command.
#
#  CLASS_NAME
#    Specifies the base class of the entry being added.
#
#  TEMPLATE_DN
#    Specifies the distinguished name, in the subscriber's name space, of the
#    template to use when creating the entry.
#
#  EVENT_ID
#    Specifies an identifier used to identify a particular instance of the
#    command.
#
#  ADD_<ATTR_NAME>
#    Specifies an attribute name/value to add with the entry, where
#    <ATTR_NAME> is literally replaced by the name of the attribute being
#    added.
#
#  PASSWORD
#    Specifies the initial password for the entry.
#
#
# REPLY FORMAT
#
#    The receiving application should respond to the add with a STATUS_LEVEL
#    and if the add suceeded, the subscriber must also return an ASSOCIATION.
#    Optionally, a STATUS_MESSAGE may also be returned to pass string messages
#    to the IDM engine for processing and logging.
#
#    If the add event does not contain values for all attributes defined in
#    the create rules, the IDM engine discards the add command for the entry.
#    When a modify command is received for this entry, IDM queries eDirectory
#    for the missing attributes.  If all attributes now have values, IDM
#    changes the modify into an add command.
#
#    The format for returning ASSOCIATION, DEST_DN, DEST_ENTRY_ID, EVENT_ID,
#    STATUS, STATUS_MESSAGE are as follows:
#
#      $idmlib->idmsetvar("ASSOCIATION", $<association>);
#      $idmlib->idmsetvar("DEST_DN", $<dest_dn>);
#      $idmlib->idmsetvar("DEST_ENTRY_ID", $<dest_entry_id>);
#      $idmlib->idmsetvar("EVENT_ID", $<event_id>);
#
#      $idmlib->status_<level>("<optional message>");
#
#        <level> may be one of the following values:
#        * success
#        * warning
#        * error
#        * retry
#        * fatal
#
#      Note:  fatal will shutdown the driver, retry will retry the event
#            later on.
#

use strict;
use IDMLib;
use Data::Dumper;

our $global_config;

# include the IDM Library
my $idmlib = new IDMLib();

$idmlib->logger($global_config->{TRACEPRIO}, "add.pl", " add invoked ");
$idmlib->trace(" *** add.pl *** ");

# retrieve any necessary information from the shim, such as CLASS_NAME
# of the object being added
my $CLASS_NAME = $idmlib->idmgetvar("CLASS_NAME");
my $CN = $idmlib->idmgetvar("ADD_CN");
my $DNS = $idmlib->idmgetvar("ADD_Surname");




# INSERT CUSTOM CODE HERE
#
# Retrieve additional information about the event and send back an
# association for this object along with a status document
#
#





# *****************************************************
# LEGAL NOTICE
#
#     This part is developed by Kevin Rasmussen
#     for TeleGreenland as part of the ISP project
#     delivered by Steria A/S.
#   
#     Steria A/S is the copyright owner of this part
#     Why they are holding the legal rights to lines
#     below.
# *****************************************************


#  Builds the DNS record informations.
my $text = "";
#my @tmp = split (/\//, $DNS);

#my $num = scalar($tmp);
my @out = map{[split /\,/, $_]}split(/\//, $DNS);

for(my $i = 0; $i<$num; $i++)
{
    my $c = $i - 1;
    my $tmptxt = @tmp[$i];
    my @tmp2 = split (/\,/, $tmptxt);
    my $num2 = scalar(@tmp2);
    #my $num2 = scalar(@tmp[$c][]);
    for(my $z = 0; $z < $num2; $z++)
    {
        my $q = $z - 1;
        $text .= $out[$i][$z];
    }
}

mkdir "/root/test/".$CN, 0755;
mkdir "/root/test/".$CN."/named", 0755;
mkdir "/root/test/".$CN."/zones", 0755;

#  ******************************************************
#  This Section is for building the Forward lookup zone.
#  ******************************************************

my $fortext = '$ORIGIN
$TTL 26000000
'.$CN.'.gl    IN SOA    GLNS01.tele.gl root.GLNS01.tele.gl (
    2008090400
    3H
    1H
    1W
    1D)
    IN NS    GLNS01.tele.gl
    IN NS    GLNS02.tele.gl
$ORIGIN '.$CN.'.gl.
www    IN A    194.177.250.98
mail.'.$CN.'.gl    A    172.30.5.168
'.$CN.'.gl    MX    mail.'.$CN.'.gl    10
';

open(FILE, ">/root/test/".$CN."/zones/".$CN."forward.gl");
print FILE $fortext;
close(FILE);

#  ******************************************************
#  This section is for building the reverse lookup zone.
#  ******************************************************

my $reverstext = 'Domæne: 10.0.0.3
';
$reverstext .= 'Kundenavn: '.$CN.'
';
$reverstext .= 'Mail reverse address: 10.0.0.4
';

open(FILE, ">/root/test/".$CN."/zones/".$CN.".in-adr.arpa.gl");
print FILE $reverstext;
close(FILE);

open(FILE, ">/root/test/".$CN."/named/test.txt");
print FILE $text;
close(FILE);

#  ***************************************************************
#  This section builds and writes the informations to named.conf.
#  ***************************************************************

my $path = "/etc/named.conf";
my $writep = ">/etc/named.conf";

my $a = 'zone "'.$CN.'.gl" in {
  allow-transfer { any; };
  file "../kunder/'.$CN.'/zones/'.$CN.'forward.gl";
  type master;
};
';

$a .= 'zone "250.177.194.in-addr.arpa" in {
  file "../reverse/250.177.194.in-addr.arpa";
  type master;
  allow-transfer { any; };
  };
';

$a .= "
";
$a .= '#VAR';


my $filetext = file_get_contents();
my $final = str_replace();

unlink($path);

open(FILE, ">".$writep);
print FILE $final;
close(FILE);

#  ***********************************************
#  This section holds our functions.
#  ***********************************************

sub file_get_contents
{
    my $filename = $path;

    my $content = "";
    open(FH, "<".$filename) or die $!;
    while(<FH>)
    {
        $content .= $_;
    }
    close(FH);

    return $content;
}

sub str_replace
{
    my $replace_this = "#VAR";
    my $with_this = $a;
    my $string = $filetext;
   
    my $length = length($string);
    my $target = length($replace_this);
   
    for(my $i=0; $i<$length - $target + 1; $i++)
    {
        if(substr($string,$i,$target) eq $replace_this)
        {
            $string = substr($string,0,$i) . $with_this . substr($string,$i+$target);
        }
    }
    return $string;
}




#  *********************************************
#  END OF CUSTOM CODE
#    This ends the copyrighted part of this
#    script.
#  *********************************************



# For the skeleton script, simply return a "Not Implemented" status
$idmlib->status_warning("Not Implemented");

******************************************************************************

Hvis jeg udkommenterer:

open(FILE, ">/root/test/".$CN."/named/test.txt");
print FILE $text;
close(FILE);

og

for(my $i = 0; $i<$num; $i++)
{
    my $c = $i - 1;
    my $tmptxt = @tmp[$i];
    my @tmp2 = split (/\,/, $tmptxt);
    my $num2 = scalar(@tmp2);
    #my $num2 = scalar(@tmp[$c][]);
    for(my $z = 0; $z < $num2; $z++)
    {
        my $q = $z - 1;
        $text .= $out[$i][$z];
    }
}

Så virker mit script i den forstand at det afviklses, så det er i denne del der er "fejl". Men jeg kan simpelthen ikke finde den.
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 07:07 #9
oh...Der er to fejl i det postede script:
#my @tmp = split (/\//, $DNS);
og
#my $num = scalar($tmp);

De skal være aktive(altså ukommenterede).
Men selvom de er det, er det samme resultat. Det virker ikke.
Avatar billede Slettet bruger
08. september 2008 - 10:10 #10
hvis du nu lige starter med at forklare hvad i alverden dette er for noget, så er det måske nemmere at løse. Hvad skal dette script gøre? Og hvorfor er den ikke dokumenteret?
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 10:23 #11
Fair.

I forbindelse med Novell iDm eksisterer der jo som bekendt en scriptdriver. Denne scriptdriver kan envoke scripts af enten Perl, python eller shell ved enten en add operation, en modify operation, delete operation, modify password operation, Query operation og move operation.
I forbindelse med at jeg er igang med at implementere IDM i en meget stor kundes kommende infrastruktur, skal blandt andet både ISP og Webhotel automatiseres. I den forbindelse er IDM ideel, bortset fra jeg ikke er den store hej til Perl som dog er tættest på PHP som jeg har stor kendskab til.

Nuvell. Dette script skal oprette zonefiler og tilføje zonefil referencer til named.conf på en DNS server, når der tilføjes en ny kunde. Det vil sige dette script vil automatisk blive kaldt og eksekveret når der tilføjes en ny kunde da det er en add operation.
Scriptet er kun på test stadiet, der vil derfor blive ændret en del på stier og den slags. Men altså: Når der oprettes en kunde oprettes der en kunde OU i eDir og under den et Userobject. i den er der via Schema extensions tilføjet et felt til DNS records som vil stå som en enkelt streng adskilt først af "/" og dernæst af ",". Denne streng skal "pakkes" ud i et to dimensionelt array og bruges til at generere zonefilerne med. Det første niveau af dette to dimensionelle array er en record, det næste er de forskellige oplysninger til den ene record.

De folders der oprettes er kun lokalt, men er for at kunne overskue kunderne hvis man skal ind og administrere noget lokalt.

Håber det gav lidt mening?
Avatar billede Slettet bruger
08. september 2008 - 10:31 #12
Og hvor er det det giver problemer? (kender ikke noget til IDM)
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 10:43 #13
Det er ikke IDM der er problemet. Det var blot for at give noget baggrundsinfo om meningen med galskaben. :)

Scriptet giver problemer i den del der danner det to dimensionelle array og for testens skyld prøver jeg at danne en streng af indholdet ved at adde til en streng(da jeg jo skal "bygge" en streng med informationer efter et helt bestemt mønster med en masse varibler som er holdt i det to dimensionelle array). Denne del af scriptet volder mig problemer.
Når jeg tager min egen del af scriptet(den del der står i custom code) og smider det over i et test script og bruger nogle prædefinerede variabler eller $ARGV og smider paramétre på, virer det fint! men det gjorde det også fra sin spæde start, men ikke i add.pl før jeg tilrettede scriptet til at være 100% "rent" eller som man siger i PHP, korrekt. Altså tror jeg at den ikke eksekverer scriptet hvis det ikke er 100% "rent" hvis du forstår?

Jeg ved fejlen er et eller andet sted i dette afsnit:

open(FILE, ">/root/test/".$CN."/named/test.txt");
print FILE $text;
close(FILE);

eller dette:

my $text = "";
my @tmp = split (/\//, $DNS);
my $num = scalar($tmp);
my @out = map{[split /\,/, $_]}split(/\//, $DNS);
for(my $i = 0; $i<$num; $i++)
{
    my $c = $i - 1;
    my $tmptxt = @tmp[$i];
    my @tmp2 = split (/\,/, $tmptxt);
    my $num2 = scalar(@tmp2);
    #my $num2 = scalar(@tmp[$c][]);
    for(my $z = 0; $z < $num2; $z++)
    {
        my $q = $z - 1;
        $text .= $out[$i][$z];
    }
}

For når jeg udkommenterer dem, bliver scriptet eksekveret.
Avatar billede Slettet bruger
08. september 2008 - 11:23 #14
my $text = "";
my @tmp = split (/\//, $DNS);
my $num = scalar($tmp);
^^ hvad sker der her?
burde det ikke være scalar(@tmp) i stedet


my @out = map{[split /\,/, $_]}split(/\//, $DNS);
for(my $i = 0; $i<$num; $i++)
{
    my $c = $i - 1;
    my $tmptxt = @tmp[$i];
    my @tmp2 = split (/\,/, $tmptxt);
    my $num2 = scalar(@tmp2);
    #my $num2 = scalar(@tmp[$c][]);
    for(my $z = 0; $z < $num2; $z++)
    {
        my $q = $z - 1;
        $text .= $out[$i][$z];
    }
}
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 11:27 #15
Well, godt set og jeg har lige ændret det. men stadig samme resultat.
Avatar billede Slettet bruger
08. september 2008 - 11:43 #16
Det er altid en god ide at skrive 'open' med en fangning af fejl, f.eks.

open(FILE, ">/root/test/".$CN."/named/test.txt") or die "cannot open file: $!";

så kan man i hvert fald tjekke om det er open delem som fejler.

forklare lige hvad det er den for-løkke skal gøre.
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 11:51 #17
For løkken skal gerne for hver gang der er data i første dimension, splitte dataen i anden dimension og samtidig gemme antal "record" i anden dimenstion i en variabel, således at vi i anden for løkke kan skrive i variablen og hele tiden vælge en ny værdi. Lyder måske lidt kryptisk, men jeg ved ikke lige hvordan jeg skulle forklare det.

Meningen er at jeg i anden forløkke skal bygge de forskellige record linjer ud fra if sætninger alt efter om det er en SOA, MX, A eller INS record osv. Derfor er jeg nødt til at kunne tjekke på hver enkelt felt, og der er en tæller jo optimal.
Avatar billede Slettet bruger
08. september 2008 - 11:56 #18
Hvad sker der her

    my $tmptxt = @tmp[$i];

smid lige en

use warnings;

i toppen af filen (efter 'use strict') og kig på hvilke advarsler den kommer med. Jeg er lidt bange for at du blander for meget PHP syntaks ind i dette.
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 12:50 #19
Hvor kan jeg se de warnings?
Jeg kan da også bare smide en -w efter #!/usr/bin/perl
Men det står jo normalt i terminalen.
Nu har jeg dog smidt det der use Warnings ind i scriptet. men hvor kan jeg så se warnings?
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 12:50 #20
Og ja, jeg ved godt det er alt for meget PHP, men det er jo også det jeg kan. :S
Avatar billede Slettet bruger
08. september 2008 - 12:58 #21
det er 'use warnings;' med småt

når du kører scriptet sender det ikke fejl et sted hen, eller kan du køre det på kommandolinien? warnings etc. kommer på STDERR så de kommer ud på kommandolinien hvis du kører scriptet fra kommandolinien. Hvis du kører scriptet gennem noget andet så må du selv finde ud af hvor STDERR bliver smidt hen. Men vi bliver nok nødt til at få fat på STDEER for at kunne debugge hvad du har gjort forkert.

Hvis du kan så meget php, hvorfor skriver du så ikke abre scriptet om til php, det kan jo også køres som scripting sprog. Man skal generelt passe lidt på med at hacke scripts til i sprog man ikke selv har styr på. (hvilket er hvorfor jeg normalt holder mig fra PHP)
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 13:07 #22
Meningen er at

my $tmptxt = @tmp[$i];

Skal indeholde strengen fra felt nummer $i fra første dimension.
Den vil for eksempel se sådan ud:

$tmptext = "dette,er,en,test"

og den vil jo så bagefter blive splittet til et array. Så der for hver felt i første dimension er et array med : @ar2[0]= dette;  @ar2[1]= er;  @ar2[2]= er;  @ar2[3]= en;  @ar2[4]= test;

Altså:
@out[(0=>[{@ar1[0]= dette},{@ar2[1]= er},{@ar2[3]= en},{@ar2[4]= test}) (1=>[{@ar2[0]= Hvorfor},{@ar2[1]= er},{@ar2[3]= det},{@ar2[4]= det?})];

Det er der der meningen med

my $tmptxt = @tmp[$i];

og derefter

my @tmp2 = split (/\,/, $tmptxt);
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 13:12 #23
jeg ville meget gerne køre det som php script, men det ville betyde at Perl scriptet skulle kalde PHP scriptet med mere end 100 parametre hvoraf nogle er sætninger med mellemrum. Derudover vil det betyde at jeg skal installere php interpretteren på mere end 50 servere over en 200MB linje(jeg skal fjernstyre dem over en Xenserver og sattelit forbindelse). Så jeg er lidt nødsaget til at få det til at virke. :(

Når jeg kører scriptet direkte på en kommando linje virker det jo. og det har det hele tiden gjort. Selv da jeg startede og kun havde en lille bitte funktionalitet som oprettede en folder og intet andet. men hvis jeg kørte scriptet via driveren, virkede den kun hvis koden var 100% korrekt. dvs det tog mig lidt tid at finde ud af hvordan jeg skulle skrive syntaksen for at få den "korrekt" nok. Da den virkede fra driverkaldet, forsøgte jeg også den tilrettede kode på en kommando linje. Virkede stadig fint.

Så det er desværre noget med at det virkelig skal være fejlfrit. :( Og selv jeg har hentet EPIC til Eclipse og forsøgt mig der, tilladder EPIC desværre alt for "løs" syntaks.
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 13:16 #24
Scalar value @tmp[$i] better written as $tmp[$i] at ./add.pl line 137.
"my" variable $num2 masks earlier declaration in same scope at ./add.pl line 140.
Scalar value @tmp[$c] better written as $tmp[$c] at ./add.pl line 140.
Global symbol "$c" requires explicit package name at ./add.pl line 140.
syntax error at ./add.pl line 140, near "]["
Execution of ./add.pl aborted due to compilation errors.

Her er kommando linjens warnings.
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 13:21 #25
fandt problemerne.... :S
Avatar billede kkrasmussen Nybegynder
08. september 2008 - 13:26 #26
Jeg takker ydmygst.
Nu fungerer det som smurt. Det var nogle @ der skulle byttes ud med nogle $ og så var det en [] der skulle slettes. Og så kører det bare.
Avatar billede Slettet bruger
08. september 2008 - 13:31 #27
Det var det jeg mente med indblandingen af php.

trict og warnings er ALTID godt at anvende i sine PERL script, det sparer en for en masse debugging tid.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester