Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

SCALAR output instead of attribute name.

by sschneid (Deacon)
on Dec 18, 2003 at 18:05 UTC ( [id://315588]=perlquestion: print w/replies, xml ) Need Help??

sschneid has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on a script to parse /etc/passwd across multiple systems. Because we don't allow root logins over ssh, using a module such as Unix::PasswdFile is not an option, so I'm attempting to do it manually. Here's some sample code:
#!/usr/local/bin/perl -w use strict; my $password; open F, '/etc/passwd'; while (<F>) { my ($nam, $pwd, $uid, $gid, $dsc, $hom, $shl) = split /:/, $_; my @attrs = \($nam, $pwd, $uid, $gid, $dsc, $hom, $shl); foreach my $attr (@attrs) { $password->{"$nam"}->{"$attr"} = $$attr; } } close F; use Data::Dumper; print Dumper $password;
I'd like my data structure to be in the form of $password->{'root'}->{'dsc'} = 'Super-user'. The problem is, my Dumper output has SCALAR listed instead of the attribute ('dsc'). Any help would be greatly appreciated. Thanks.

-s.

Replies are listed 'Best First'.
Re: SCALAR output instead of attribute name.
by chromatic (Archbishop) on Dec 18, 2003 at 18:25 UTC

    It looks like you're expecting a reference to, say, $nam to stringify to nam. It doesn't, because the names are there for your convenience, not Perl's. I'd write something like this:

    my $password = {}; while (<F>) { my ($name, @attributes) = split(/:/, $_); my %attributes; @attributes{qw( pwd uid gid dsc hom shl )} = @attributes; $password->{$name} = \%attributes; }
Re: SCALAR output instead of attribute name.
by blokhead (Monsignor) on Dec 18, 2003 at 18:27 UTC
    I think you are slightly confused about references. Taking the reference of a variable does not return its name (although this is a clever idea). Is this why you expect @attrs to contain qw(nam pwd uid ..)?

    The name of a variable can be used as a "soft reference" (only when the referent is a symbol table variable and only when in no strict 'refs'). But think of it, not all scalar values even have names, and some have many! Because of this, taking a reference to any variable using the backslash operator creates a special "hard reference" scalar. When you print out something of this reference type, you get SCALAR(0x81717c4) (if the referent is a normal scalar). Perhaps consult perlreftut for more detailed info?

    A better way to fill your hash the way you want is like this:

    my @fields = qw/nam pwd uid gid dsc hom shl/; while (<F>) { my %attrs; @attrs{@fields} = split /:/, $_; $password->{ $attrs{nam} } = \%attrs; }
    Again, you'll need an explicit list of keys for the hash, as you can't extract the attribute names from the variables.

    blokhead

      Fantastic. Thanks a bunch.

      -s.
Re: SCALAR output instead of attribute name.
by Zaxo (Archbishop) on Dec 18, 2003 at 18:27 UTC

    See perldoc getpwent

    That will avoid messing directly with /etc/passwd. It is portable across platforms and works with shadow and other variants.

    After Compline,
    Zaxo

      I wasn't looking for portability across platforms, I was looking for something to work on multiple remote hosts. Unless I rework the script into a client-server design, this still doesn't look like it'll work for me. As it stands (and for simplicity sake), I'm cating /etc/passwd over ssh, and parsing what is returned.

      -s.

        With ssh or scp, you can send your portable script to your account on each host. Then when you want to poll hosts for their user accounts, ssh -2 user@host ./myscript.pl for each host in your polling script.

        No client/server involved but portability matters.

        After Compline,
        Zaxo

Re: SCALAR output instead of attribute name.
by hardburn (Abbot) on Dec 18, 2003 at 18:34 UTC
    my @attrs = \($nam, $pwd, $uid, $gid, $dsc, $hom, $shl);

    You're assigning a refernce to an array into an array. I think what you wanted was:

    my @attr = ($nam, $pwd, $uid, $gid, $dsc, $hom, $shl);

    You also appear to be attempting to make a symbolic ref when you assign to the hash. Symoblic refs are generally something to be avoided, and in any case will only work with package variables (such as those declared with our) not lexicals (like my vars).

    Because we don't allow root logins over ssh, using a module such as Unix::PasswdFile is not an option . . .

    1. Disallowing root logins over ssh is fine, but don't they even allow su or sudo? In fact, you should be using those even if you're logging in locally.
    2. Even if you can't get root access, you can install modules to an unprivileged directory and point Perl to it, or you can copy-and-paste the source from the module.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    : () { :|:& };:

    Note: All code is untested, unless otherwise stated

      You're assigning a refernce to an array into an array.

      No; there's only one array in that line. The reference operator distributes over a list, returning a list of references, not an anonymous array.

      You're assigning a refernce to an array into an array.

      Ummm, no. He's assigning a list of references into an array.

      #!/usr/bin/perl -l my @a = qw(a b c); my @b = \(@a); print "\@a contains: @a"; print "\@b contains: @b"; __END__ @a contains: a b c @b contains: SCALAR(0x811b15c) SCALAR(0x811b240) SCALAR(0x811b294)

      What you are thinking of is [ LIST ].

      1. Disallowing root logins over ssh is fine, but don't they even allow su or sudo? In fact, you should be using those even if you're logging in locally.

      Yes, absolutely. But I'm looking to grab a giant list of users from our 90-some *nix boxes. I could use a client-server design, but decided it'd be just as easy to cat /etc/passwd over a (non-privileged) ssh connection and parse the return results on whatever machine the script is being run from.

      Make more sense? I'm avoiding Unix::PasswdFile becuase it requires root privileges to use, and I don't want the script to be run as root.

      -s.

        Actually, after looking over some of the source code to Unix::PasswdFile and its parent Unix::Configfile, I wouldn't use it either. It's internals are awful.

        I don't know why you need to be root to use it, though. In any case, there are other /etc/passwd parsing modules on CPAN.

        ----
        I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
        -- Schemer

        : () { :|:& };:

        Note: All code is untested, unless otherwise stated

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://315588]
Approved by Zaxo
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2024-03-28 08:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found