If you really need to traverse a directory tree, please read the article about Path::Iterator::Rule. This article is mostly for those who would like to see the use a simple queue, for the generic problem of traversing a tree-like structure.

In another article you can find a solution using recursion. This time we are going to use a queue. That is a data structure where we can push new items to the end and pull items from the beginning. In the computational world such data structures are called FIFO - First in First out, because the first item that gets in the queue is the first that will leave it. Even if that happens later on. In general the sooner an item gets in the queue, the sooner it will get processed.

In Perl, a regular array can be used as a queue. We can use the >push function to add more elements to the "end" of the array (the side where the index has the highest number), and we can use the shift function to fetch a value from the "beginning" of the array. The value at index 0.

Directory

We will use the same directory structure we used with the recursive solution.

root
root/a
root/a/aa.txt
root/a/foo
root/a/foo/bar.txt
root/a/foo/baz.txt
root/a/foo.txt
root/b.txt
root/c

use strict;
use warnings;
use 5.010;

my $path = shift || '.';

traverse($path);

sub traverse {
    my @queue = @_;

    while (@queue) {
        my $thing = shift @queue;
        say $thing;
        next if not -d $thing;
        opendir my $dh, $thing or die;
        while (my $sub = readdir $dh) {
            next if $sub eq '.' or $sub eq '..';
            push @queue, "$thing/$sub";
        }
        closedir $dh;
    }
    return;
}

The beginning is simple, we allow the user to supply the directory name on the command line, we shift it out from @ARGV, but if no value was supplied we default to '.' which is the current directory.

Then we call the traverse() function and pass the starting path to it. Actually we don't have to have subroutine for this, but having subroutines usually lead to cleaner code. Certainly more reusable code.

Inside the subroutine we declare the @queue array with the values we just got from the caller. (In our case this will be one value.) The while loop will as long as there are items in the queue. (An array in scalar context will return the number of elements it contains. If it has any elements then it is a positive number which is considered true. When the array is empty the number of elements is 0 which is considered false in Perl.

my $thing = shift @queue; fetches the first element, and then we print it. If this is NOT a directory, we can skip the rest of the loop and go to handle the next item.

The next section then will read in the items from the immediate subdirectory and add them to the end of the queue.

   opendir my $dh, $thing or die;
   while (my $sub = readdir $dh) {
       next if $sub eq '.' or $sub eq '..';
       push @queue, "$thing/$sub";
   }
   closedir $dh;

How can we know the queue will end?

We know we are handling a tree structure that has a limited depth and we know every directory has a limited number of entries in it. (We also assume no loops created by symbolic links.) So we know we have a limited number of items to print. Once all of them were processed the @queue array will become empty and the main while loop will end.

The result

Running perl queue.pl root give the following output:

$ perl queue.pl root
root
root/a
root/b.txt
root/c
root/a/aa.txt
root/a/foo
root/a/foo.txt
root/a/foo/bar.txt
root/a/foo/baz.txt

The list of items is exactly the same as in the case of the recursive solution, though the order of the items is different.