`dir $dosdir`; stopped working

Greetings:

I have a perl script that's been running for years.  I'm using 5.6.1 by activestate for Win32 on a NT4.0 server.

A week or so ago, my script stopped working.  I suspect it's due to someone patching the NT server (I don't administer it).  But I have no way to know...

The problem appears to be at least with my command which gets a sorted by date directory list.  I ran this debug snippet to test:

@filelist=`dir \httpd\testing /OD /B`;

print "BEGIN\n";
for (@filelist) {
      chomp;
      $file = $_;
  print "Processing: $file\n";
}
print "END\n";


All I get for output is:

BEGIN
END

The directory has 3 files in it and all are not read-only, just archive flag set.

Any suggestions?

Thanks very much for the help.  I am not a perl guru so if possible answers in laymen form appreciated.

Thanks,
Scott








scotthortonAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

sstoukCommented:
I suppose you already restarted the NT Server and tested your script again?
0
sstoukCommented:
As a worst-case scenario here's the modification for your script:
#######################################
# @filelist=`dir \ /OD /B`;
@filelist2 = main::ListFiles("/httpd/testing",0,"*.*");
print "BEGIN\n";
for (@filelist2) {
# chomp;
     $file = $_;
  print "Processing: $file\n";
}
print "END\n";


##############################################################################
sub main::ListFiles
{
my(@FILENAME) = undef;
my($dirname) = $_[0];
my($fullnameswitch) = $_[1];
my($pattern) = $_[2];
my($count) = 0;
my($file) = undef;
if($pattern) {$pattern =~ s/\*/\.\*/g; $pattern = "^"."$pattern"."\$"};
if ($dirname =~ m!/!)
{
      unless ($dirname =~ m!/$!)
      {
      $dirname = "$dirname"."/";
      };

} else {
            unless ($dirname =~ m!\$!)
            {
            $dirname = "$dirname"."\\";
            };
      };
opendir(DIR, $dirname) or warn "can't opendir $dirname: $!";
      while (defined($file = readdir(DIR)))
      {
      next if $file =~ /^\.\.?$/;
      next if (-d "$dirname$file");
            if (($file =~ /$pattern/g) && (-f "$dirname$file"))
            {
            # print "FILE: $file\n<br>";
                  if ($fullnameswitch)
                  {
                  $FILENAME[$count] = "$dirname"."$file";
                  $FILENAME[$count] =~ s/\\\\/\\/;
                  $FILENAME[$count] =~ s/\\/\//;
                  $count++;
                  } else {
                        $FILENAME[$count] = $file;
                        $count++;
                        };
            } else {
                  
                  };
      }
closedir(DIR);
return @FILENAME;
};
##############################################################################
0
scotthortonAuthor Commented:
Yes, I restarted server first, no avail.

As for the code above, it does not sort file list in date order.  Does it?  Processing the files in date order is a requirement for the rest of the app.

Thanks,
Scott


0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

ozoCommented:
@filelist=`dir \httpd\testing /OD /B`;
should be
@filelist=`dir \\httpd\\testing /OD /B`;
0
scotthortonAuthor Commented:
My apologies.  I do have the "\\" in the existing code.  I couldnt' cut and paste because the source PC is on a secure network.  Sorry, but thanks very much for the detailed look.  Still not working.  Same script works on a different computer, pretty much points at something they've done to the NT server.  I and the account the script runs under have full administrative rights and the server is not a member of any other domain.

:-(

0
kanduraCommented:
here's a short subroutine that will get your list, sorted by modification date (oldest first). Pass the directory as first and only argument.

sub my_dir
{
      my $dir = shift;
      
      opendir(DIR, $dir) or die "Couldn't read dir $dir: $!";
      my @files = map { $_->[1] }                         # return filenames
                  sort { $b->[0] <=> $a->[0] }              # sort on modification time
                  map { [ -M "$dir/$_", $_] }                  # do a Schwartzian transform
                  grep { !/^\.+$/ }                         # skip . and ..
                  readdir(DIR);
      closedir DIR;

      @files;      # return as array
}
0
ext2Commented:
does

   dir \httpd\testing /OD /B

work from the DOS command prompt?
0
Teh_CrazeCommented:
Here; Make sure, when specifying directories, or when any backslash is needed, to escape it, and, for safty, allways put a trailing backslash to indicate it's a directory.

@filelist=`dir \\httpd\\testing\\ /od /b`;

print "BEGIN\n";
for (@filelist) {
     chomp;
     print "Processing: $_\n";
}
print "END\n";



0
kanduraCommented:
Hi Scott,

I don't think you told us this, but what's the output from that dir command when you run it directly from the command prompt?
Is your script on the same drive as that httpd directory?
What happens when you change the `dir ...` to a simple `dir` command? Does your script list the same output as a direct dir command?

Just checking,
Kandura

PS, did you get a chance to test my subroutine? It should work, or tell you why it doesn't work. And it's platform-independent ;^)
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
scotthortonAuthor Commented:
Kandura, et.al.:

THanks very much for the help.  I found the problem on my own.  It was where someone installed something on the NT server that inserted a non-existant directory into the path.  As someone usggested above, I of course tried the "dir" command from the directory and it worked.  Funny thing was though that a ls would not, even though a ls.exe was inthe path.  Also, piping through more didn't work, but more was int he path.  Once I anaylzed the PATH and found the bogus dir I removed it and all was well again.  

Kandura:

I accepted you answer because I trust it would have fixed me regardless since it was platform independent making no external calls. I have needd this code snippet for other things.  Thanks for it.  I'm a perl beginner, any chance I could get you to disect it and elaborate on your code-comments me some more?


sub my_dir
{
     my $dir = shift;
     
     opendir(DIR, $dir) or die "Couldn't read dir $dir: $!";
     my @files = map { $_->[1] }                     # return filenames
               sort { $b->[0] <=> $a->[0] }             # sort on modification time
               map { [ -M "$dir/$_", $_] }                 # do a Schwartzian transform
               grep { !/^\.+$/ }                     # skip . and ..
               readdir(DIR);
     closedir DIR;

     @files;     # return as array
}


Cheers,
Scott



0
kanduraCommented:
Hi Scott,

I'll give it a try. Basically what I do is using readdir to get a list of entries in the specified directory.
The command to get the @files should be read backwards:
- readdir(DIR)
       this returns a list of all the entries in the directory
- grep { !/^\.+$/ }
        this removes all the files or directories whose name consists only of dots (usually just . and ..)
        it works by matching every element in the list returned by readdir to the given regexp,
        and only letting those through that do _not_ match (hence the !)

Now, the next bits are really just a fancy way to sort on the modification date. I'm using a Schwartzian Transform here
to optimize the sorting routine.
I could have just written the sort function in such a way that you compare the modification date for each pair, but I want to avoid
having to fetch the date again and again for each comparison. So what I do is prepare this before sorting: for every filename returned by
grep, I construct an anonymous array. The first element is the modification date, and the second is the original filename.
Now I can sort those anonymous arrays on the first element. You see that I only have to compare the pre-calculated values.
Finally, I return the original filename that was the second element in the anonymous arrays.
I've concatenated all those steps in one long command to avoid creating all kinds of temporary arrays (actually that is part of the Schwartzian Transform).

Let me write it out again, but in the right order, and with temp arrays:

my @all_files = readdir(DIR);                                                 # get all entries
my @grep_files = grep { ! /^\.+$/ } @all_files;                        # weed out . and ..
my @date_files = map { [ -M "$dir/$_", $_ ] } @grep_files;       # pre-calculate the modification dates
my @sort_dates = sort { $b->[0] <=> $a->[0] } @date_files;   # sort on the first entry in each [ ] array
my @sorted = map { $_->[1] } @sort_dates;                            # get only the filenames back
return @sorted;

As you can see, that is quite a bit longer and less efficient. Of course you can reuse a temp array, but this is for readability.
What the ST does, is eliminating all the assignments to the temporary arrays, by taking the output of one command as the input for the next.

Hope this clarifies it a bit :-)

Kandura
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Perl

From novice to tech pro — start learning today.