Harry Putnam wrote:
> "Rob Dixon" <[EMAIL PROTECTED]> writes:
> >
> > This code will build a map of 'stat' type values to the seven type
> > operators that you list. Not all of them may be active on your system.
> > You can obviously modify the code to return the value you want.
> > You need to import the symbolic mode values using Fcntl before this
> > will work.
>
> Thanks for the code.
>
> > Let us know if anything needs explaining.
>
> Just about every line is mystery to me... hehe.
>
> But I'll only ask one question until I study it some more.
> >     my %types;
>      ^^^^^^^^^^^
> Why is that line there?

It implements a persistent hash local to the block. That's why the
extra pair of braces is there - it contains just the hash
and the subroutine that uses it. If it were declared within the
subroutine it would get destroyed after each call and would
need reinitialising each time. As it is the 'unless' statement
initialises once and it stays that way. It's like a 'static'
declaration in C.

> Whats more noticable is that it doesn't work very well as is.
>
> I think its due to  `stat' itself more than anything else though.
> Or at least the file tests themselves.
>
> >   use strict;
> >   use Fcntl ':mode';
> >
> >   print filetype('/home/rob/dir'), "\n";
> >   print filetype('/home/rob/script'), "\n";
> >
> >   {
> >     my %types;
>
>
> >
> >     sub filetype {
> >
> >       unless ( %types ) {
> >         @types{ map eval || '', qw/S_IFREG S_IFDIR S_IFLNK S_IFBLK S_IFCHR S_IFIFO 
> > S_IFSOCK/ }
> >             = qw/-f -d -l -b -c -p -S/;
> >         delete $types{''};
> >       }
> >
> >       my $file = shift;
> >       my $type = (stat $file)[2] & S_IFMT;
> >
> >       return $types{$type};
> >     }
> >   }
> >
> > > > OUTPUT
> >
> >   -d
> >   -f
>
> Consider the input files as shown:
>
> #!/usr/local/bin/perl -w
> use strict;
> use Fcntl ':mode';
>
> print filetype('/home/reader/.bashrc'), "\n"; ## symlink to regular file
> print filetype('/home/reader/scripts'), "\n"; ## symlink to directory
> print filetype('/home/reader/.abbrev_defs'), "\n"; ## regular file
> print filetype('/home/reader/print'), "\n";        ## regular directory
>
>
> {
>   my %types;
>
>   sub filetype {
>
>     unless ( %types ) {
>       @types{ map eval || '', qw/S_IFREG S_IFDIR S_IFLNK S_IFBLK S_IFCHR S_IFIFO 
> S_IFSOCK/ }
>           = qw/ -f -d  -l -b -c -p -S/;
>       delete $types{''};
>     }
>
>     my $file = shift;
>     my $type = (stat $file)[2] & S_IFMT;
>
>     return $types{$type};
>   }
> }
>
> OUTPUT>>>>
> -f
> -d
> -f
> -d
>
> Wrong on %50.
>
> But then those tests -f -d using the normal tests also fail.
> (Remember ~/.bashrc is a symlink)
>
>   $ perl -e 'if(-f "/home/reader/.bashrc"){
>     print "/home/reader/.bashrc is a regular file\n";}'
>       /home/reader/.bashrc is a regular file
>
> Wrong again ... its a symlink
>
> Where as Unix `stat' knows its a symlink:
> $ stat /home/reader/.bashrc
>   File: "/home/reader/.bashrc" -> "/cvs_buf/reader/home/reader/.bashrc"
>   Size: 35              Blocks: 0          IO Block: -4611717010911391744 Symbolic 
> Link
>                                                                           
> ^^^^^^^^^^^^^
> Device: 307h/775d       Inode: 111745      Links: 1
> Access: (0777/lrwxrwxrwx)  Uid: (  500/  reader)   Gid: (  500/  reader)
> Access: Sat Jun  7 08:45:07 2003
> Modify: Fri May 30 18:39:02 2003
> Change: Fri May 30 18:39:02 2003
>
> ================================================
>
> The -f test fails on unix too.  But as mentioned unix `stat' knows
> the difference.
>
> Unix `file' knows the difference.
>
> Maybe perl `stat' also knows the difference but still not clear how
> to extract the info from it.

Yes. My apologies - I'm travelling at the moment and I have no Unix
system with me to test on. Change that line to use 'lstat' instead:

  my $type = (lstat $file)[2] & S_IFMT;

the difference being that 'stat' on its own follows the symlink trail to
the end and reports on the file at the end. Lstat just reports on what you
have named. The -d and -f operators will do the same as 'stat', but you
should find that -l is also true which, if you check it first, will tell
you that it is actually a symlink to whatever -d and -f indicate.

HTH,

Rob




-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to