Schrift
[thread]12230[/thread]

Hash-Slice und die Ausgabe...

Leser: 1


<< |< 1 2 >| >> 20 Einträge, 2 Seiten
Duff
 2008-07-23 19:02
#112510 #112510
User since
2006-10-06
283 Artikel
BenutzerIn

user image
Hallo,

ich habe folgendes Problem und blicke einfach nicht mehr durch.

Ich möchte aus der /etc/passwd alle Benutzer in einem Hash speichern und als Wert sollen dann noch ein paar weitere Informationen aus der DAtei gespeichert werden.

Dass Ganze hat soweit auch funktioniet, nur komme ich mit der Ausgabe ohne print Dumper nicht zurecht.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
sub parse_passwd {
        open(FILE,"<","$passwd");
        while(<FILE>) {
                # $user = Login-Name des Benutzers
                # $x    = stand früher das verschlüsselte Passwort, welches nun in /etc/shadow steht 
                # $id   = User-ID des Benutzers
                # $gid  = ID der Hauptgruppe des Benutzers
                # $com  = Kommentar/Beschreibung des Benutzers
                # $home = Home-Verzeichnis des Benutzers
                ($user,$x,$uid,$gid,$com,$home)=split(/:/,$_);
                if($uid >= 1000 && $user =~ /^[A-Za-z0-9]+$/) {
                        push @{$passwd{$user}},"$uid $gid $com $home" unless exists $passwd{$user};
                }
        }
        close(FILE);
        return \%passwd;
}


sub print_passwd {
        my $var=shift;
        print Dumper($var);
}

my $get_passwd=parse_passwd();
print_passwd($get_passwd);


Die Ausgabe mit Dumper sieht so aus:
Code: (dl )
1
2
3
4
5
6
7
8
$VAR1 = {
'daniel' => [
'1000 1000 daniel,,, /home/daniel'
],
'sshuser' => [
'1006 1010 /mirror/home/sshuser/'
]
};
D'OH
Daniel
Linuxer
 2008-07-23 19:14
#112512 #112512
User since
2006-01-27
3890 Artikel
HausmeisterIn

user image
Hi, wo ist nun Dein Problem?

parse_passwd() liefert eine Hash-Referenz zurück.

Jeder Schlüssel in diesem Hash entspricht einem Usernamen und jeder dazugehörige Wert ist eine ArrayReferenz.

Warum Du allerdings die verschiedenen Werte in einen String packst und dann nur ein Array-Element hast, kannst Du nur selber wissen.

Schnellschuss:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
sub print_passwd {
  my $hash_ref = shift;

  for my $k ( keys %$hash_ref ) {
    my $user = $hash_ref->{$k};
    my $data = $hash_ref->{$k}->[0];

    print "$user : $data\n";
  }
}


Code ungetestet.
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
LanX-
 2008-07-23 19:23
#112515 #112515
User since
2008-07-15
1000 Artikel
BenutzerIn

user image
du willst ein hashslice aus einer hashref?

Code (perl): (dl )
1
2
 $hash_ref={a=>1,b=>0,c=>2};
 print @$hash_ref{a,c};


oder wilst du einfach alle values ausgeben?
Code (perl): (dl )
print values %$hash_ref;


mit join kannst du noch trenner einfügen...

EDIT: sorry das Problem ist wohl etwas "verschachtelter" als der Titel Hashslices vermuten lässt ; )
Duff
 2008-07-23 19:23
#112516 #112516
User since
2006-10-06
283 Artikel
BenutzerIn

user image
Danke für die super schnelle Antwort.

my $user = $k funktioniert mit deinem oberen Code-Beispiel.


Aber wie würdest du das parsen der Datei /etc/passwd "besser" machen???
Möchte es ja richtig lösen.

Danke.
D'OH
Daniel
Duff
 2008-07-23 19:27
#112517 #112517
User since
2006-10-06
283 Artikel
BenutzerIn

user image
Würde den String gerne als Array haben bzw. speichern.
D'OH
Daniel
Linuxer
 2008-07-23 19:34
#112519 #112519
User since
2006-01-27
3890 Artikel
HausmeisterIn

user image
Duff+2008-07-23 17:23:56--
Danke für die super schnelle Antwort.

my $user = $k funktioniert mit deinem oberen Code-Beispiel.


Aber wie würdest du das parsen der Datei /etc/passwd "besser" machen???
Möchte es ja richtig lösen.

Danke.


Ah, das kommt bei Schnellschüssen raus, wenn das Hirn noch bei den eigenen Skripten hängt. $k ist ja bereits der Username...

Ich würde die zusätzlichen Werte direkt in den Array legen und erst bei der Ausgabe die Elemente des Arrays zu einem String zusammenführen.

Hätte den Vorteil, dass Du, wenn das mal erweitert werden soll und Du die anderen Werte prüfen/abfragen/verarbeiten willst, Du mit dem Array-Elementen direkt arbeiten kannst und nicht erst aus dem String schneiden musst.

Und ein Array für ein einzelnes Element ist neudeutsch oversized. Wenn es nur ein Element ist, reicht ein Skalar als Hash-Value.
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
Duff
 2008-07-23 20:15
#112522 #112522
User since
2006-10-06
283 Artikel
BenutzerIn

user image
Sorry, aber verstehe nicht ganz, wie du dass meinst.

Soll ich beim Erzeugen des Hashes, die Werte schon als Array übergeben?
Wenn ja, wie?

Oder soll ich aus dem String ein Array machen durch z.B. eine for-Schleife?
D'OH
Daniel
Linuxer
 2008-07-23 20:25
#112523 #112523
User since
2006-01-27
3890 Artikel
HausmeisterIn

user image
Hi,

nun bin ich zuhause und kann mich mehr damit beschäftigen;
basierend auf Deinem Ausgangsskript würd ich das so implementieren.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/usr/bin/perl
# vi:ts=4 sw=4 et:
use strict;
use warnings;

#> global variables
#> ----------------------------------------------------------------------------

my $file = '/etc/passwd';


#> sub routines
#> ----------------------------------------------------------------------------

sub parse_passwd {
    my $passwdfile = shift;
    my %passwd     = ();

    open my $fh, '<', $passwdfile or die "$passwdfile: open(ro) failed: $!\n";

    while ( my $line = <$fh> ) {

        chomp $line;
        my ( $user, $pw, $uid, $gid, $com, $home ) = split m{:}, $line;

        if ( $uid >= 1_000 and $user =~ m{\A[A-Za-z0-9]+\z} and !exists $passwd{$user} ) {
            push @{ $passwd{$user} }, $uid, $gid, $com, $home;
        }
    }

    close $fh;

    return \%passwd;
}

sub print_passwd {

    my $hash_r = shift;

    for my $user ( keys %$hash_r ) {

        # unformatierte ausgabe
        print "$user: @{ $hash_r->{$user} }\n";

        # formatierte ausgabe
        printf "%s: %d %d '%s' %s\n", $user, @{ $hash_r->{$user} };

        # nur user listen, die nicht gid==100 sind
        if ( $hash_r->{$user}->[1] != 100 ) {
            printf "%s: %d %d %s %s\n", $user, @{ $hash_r->{$user} };
        }
    }
}



#> main script
#> ----------------------------------------------------------------------------


print_passwd( parse_passwd( $file ) );

__END__


Noch besser lesbar wird es, wenn Du anstatt des HoA (Hash of Array) einen HoH (Hash of Hash) verwendest. Speziell, wenn Du später auf einzelne Elemente zugreifen willst, ohne dass Du Dir merken musst, hinter welchem Index sich welcher Wert versteckt.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/perl
# vi:ts=4 sw=4 et:
use strict;
use warnings;

#> global variables
#> ----------------------------------------------------------------------------

my $file = '/etc/passwd';


#> sub routines
#> ----------------------------------------------------------------------------

sub parse_passwd {
    my $passwdfile = shift;
    my %passwd     = ();

    open my $fh, '<', $passwdfile or die "$passwdfile: open(ro) failed: $!\n";

    while ( my $line = <$fh> ) {

        chomp $line;
        my ( $user, $pw, $uid, $gid, $com, $home ) = split m{:}, $line;

        if ( $uid >= 1_000 and $user =~ m{\A[A-Za-z0-9]+\z} and !exists $passwd{$user} ) {
            $passwd{$user} = {
                gid     => $gid,
                uid     => $uid,
                comment => $com,
                homedir => $home,
            };
        }
    }

    close $fh;

    return \%passwd;
}

sub print_passwd {

    my $hash_r = shift;

    for my $user ( keys %$hash_r ) {

        # nur user listen, die nicht gid==100 sind
        if ( $hash_r->{$user}->{gid} != 100 ) {

            printf "%s: %d %d %s %s\n", $user, 
              @{$hash_r->{$user}}{ qw( uid gid comment homedir) };
        }
    }
}


#> main script
#> ----------------------------------------------------------------------------


print_passwd( parse_passwd( $file ) );


__END__

meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
Duff
 2008-07-23 21:12
#112530 #112530
User since
2006-10-06
283 Artikel
BenutzerIn

user image
Danke für dieses super ausführliche und übersichtlich gut programmierte Code-Stück (eigentlich ja schon Skript).

Hätte aber mal wieder ne Frage:
1.) In Zeile 26 schreibst du als regex "m{\A[A-Za-z0-9]+\z}". Was bedeutet nochmals das \A...\z dazwischen? (so eine Art Wortgrenze?)

2.) Werden mit dem Ausdruck in Zeile 51 "@{$hash_r->{$user}}{ qw( uid gid comment homedir) };" die einzelnen Elemente aus dem Zweiten Hash durchlaufen, indem ich dort die Schlüssel angebe?
D'OH
Daniel
Linuxer
 2008-07-23 21:29
#112532 #112532
User since
2006-01-27
3890 Artikel
HausmeisterIn

user image
Duff+2008-07-23 19:12:33--
Hätte aber mal wieder ne Frage:
1.) In Zeile 26 schreibst du als regex "m{\A[A-Za-z0-9]+\z}". Was bedeutet nochmals das \A...\z dazwischen? (so eine Art Wortgrenze?)


^ und $ matchen auf Zeilenanfang und Zeilenende, während \A und \z auf Stringanfang und Stringende matchen...

Duff+2008-07-23 19:12:33--
2.) Werden mit dem Ausdruck in Zeile 51 "@{$hash_r->{$user}}{ qw( uid gid comment homedir) };" die einzelnen Elemente aus dem Zweiten Hash durchlaufen, indem ich dort die Schlüssel angebe?


Hatte mir schon gedacht, dass dazu eine Rückfrage kommt ;o))
Ja, der Ausdruck liefert die Werte zu den genannten Schlüsseln aus dem inneren Hash.
Der Ausdruck dereferenziert die mit $hash_r->{$user} bezeichnete Hash-Referenz als Hash-Slice.
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!
<< |< 1 2 >| >> 20 Einträge, 2 Seiten



View all threads created 2008-07-23 19:02.