Perl | Recursive Subroutines - GeeksforGeeks

19 Jan, 2022
Prerequisite: Recursion in PerlRecursive means pertaining to or using a rule or procedure that can be applied repeatedly. It is the process of defining a function or calculating a number by the repeated application of an algorithm. Recursive Subroutine is a type of subroutine that calls itself as part of its execution or is in a potential cycle of function calls. Perl provides us with the flexibility to use subroutines both iteratively and recursively. A simple example showing the use of recursive subroutine in Perl would be that calculating the factorial of a number.Example : 
Perl
#!/usr/bin/perl   # Perl Program to calculate Factorial sub factorial{       my $n = $_[0];   # checking if that value is 0 or 1if ($n == 0 || $n == 1){    return 1;}   # Recursively calling the function with the next value# which is one less than current oneelse{    return $n * factorial($n - 1);}}   # Driver Code$n = 7;   # Function call and printing result after returnprint "Factorial of a number $n is ", factorial($n);
Factorial of a number 7 is 5040
 
Traversing a directory tree means to iterate over or to print each file and sub-directories within a root directory. The directory tree is a representation of the sub-directories and files within sub-directories and other files within the directory in the form of a tree denoting the parent-child relationship between these directories and respective files. Both Unix and Windows systems organize file directories into a tree structure. Although in Perl, traversing a directory tree or walking a directory tree can be done both iteratively and recursively, but we often use the later one when the number of files or sub-directories inside our root folder is very large. This is because of the fast and less number of lines of code written in recursive function in comparison to an iterative one. The later is used when the corresponding number of files are less in number. We’ll use File::Find to traverse the file system iteratively and collect the filenames.  
Syntax : use File::Find; find(\&wanted, @directories_to_search); sub wanted { ... }use File::Find; finddepth(\&wanted, @directories_to_search); sub wanted { ... }use File::Find; find({ wanted => \&process, follow => 1 }, ‘.’);  
Example :  
Perl
#!/usr/bin/perluse strict;use warnings;     use File::Find::Rule;use File::Basename qw(basename);     my $loc = "C:\Users\GeeksForGeeks";my $file = 'final.txt';my $expected = <STDIN>;chomp $expected;     open(my $fh, '<', $expected) ordie "Could not open '$expected' $!\n"; open(my $out, '>', $file) ordie "Could not open '$file' $!\n";     my @paths = File::Find::Rule->file->name('*.pdf')->in($loc);my @files = map { lc basename $_ } @paths;my %case = map { $_ => 1 } @files;     print $out "This file has been copied from ($loc)$file:\n";while (my $name = <$fh>){    chomp $name;    if ($case{lc $name})    {        print "$name found\n";    }    else    {        print $out "$name\n";    }}close $out;close $fh;
Output: Source file gets copied to the destination file  
In the coming section, we will discuss the Recursive traversal of the root directory. 
The problem with the iterative solution of traversal apart from its slow speed and more lines of code is the fact that all the sub-directories within the root directory must have the same orientation and the same number of files within them. Otherwise, the traversal can become a complex task. Recursive solution plays a better role in overcoming the problem with the iterative solution. Example (Recursive) :  
Perl
#!/usr/bin/perl # Perl recursive Program to walk# through a directory treeuse strict;use warnings;use 5.010; my $loc = shift || '.'; # Calling walk subroutine with# the location of the root directorywalk($loc); # Subroutine definitionsub walk{    my ($case) = @_;     # If case is not a directory itself    return if not -d $case;         # If case is a directory    opendir my $dh, $case or die;     while (my $sub = readdir $dh)    {        next if $sub eq '.' or $sub eq '..';        say "$case/$sub";        walk("$case/$sub");    }    close $dh;    return;}
Output : 
The above code will let you loop over each file in the root directory and all the sub-directories present in the root directory along with the files and directories within these sub-directories. 
The top-down approach basically divides a complex problem or algorithm into multiple smaller parts (modules). These modules are further divided until the resulting module is a program which can not be further decomposed. Here, we first initialize a variable called $case which keeps hold of the file or the directory being iterated or looped over. Then if it’s a file, then the function simply prints its name and loop over to next file or directory or else if the $case is a directory, then it calls the subroutine again with the directory location as the current directory location and then loop over all the files and sub-directories within that directory. After the completion of the inner function, the pointer returns back to the location of the outer directory and print its name and then moves to the next file or the directory present in the root directory. This is actually a typical Top-Down Approach used in Perl for traversing or walking over a directory tree.Example :  
Perl
use strict;use warnings;use 5.010; my $loc = shift || '.'; walk($loc); sub walk{    my ($case) = @_;         say $case;    return if not -d $case;    opendir my $dh, $case or die;    while (my $sub = readdir $dh)    {        next if $sub eq '.' or $sub eq '..';         walk("$case/$sub");    }    close $dh;    return;}
Output :  
The code explained in the section Recursively traversing a directory tree is an example of the Top-Down Approach used in Perl. 
Note : The above Output image shows a small portion of the complete output as there are a lot of files and subdirectories inside the root directory. This code works fine for folders and directories with a small number of sub-directories.
 
A recursive function has the following general form:  
Function( arguments ) {if a simple case, return the simple value // base case / stopping condition else call function with simpler version of problem }  
Example : 
Perl
#!/usr/bin/perl # Perl Program to calculate Factorialsub myfunc{    my $n = $_[0];         # checking if that value is    # greater than 0 or not    if ($n <= 0)    {        print "Now, You are on GFG portal.\n";    }         # Recursively calling function with    # the next value which is one less    # than current one    else    {        print "$n\n";        myfunc($n - 1);    }} # Driver Code # Function callmyfunc(3);
Output:  
For a recursive function to stop calling itself we require some type of stopping condition. If it is not the base case, then we simplify our computation using the general formula. A recursive function has two major parts. The first one checks for some condition and returns if that condition was met. This is called the halting condition, or stop condition. Then at some later point in the function, it calls itself with a different set of parameters than it was called earlier. 
 
It comes with the positives of writing cleaner and simpler short code.It is also efficient in terms of time if used with memorizationPerforms better in solving problems based on tree structures.
It comes with the positives of writing cleaner and simpler short code.
It is also efficient in terms of time if used with memorization
Performs better in solving problems based on tree structures.
 
germanshephered48
Picked
Perl
Perl
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Perl | Arrays (push, pop, shift, unshift)
Perl | Polymorphism in OOPs
Perl | Arrays
Perl Tutorial - Learn Perl With Examples
Use of print() and say() in Perl
Perl | length() Function
Perl | join() Function
Perl | Basic Syntax of a Perl Program
Perl | substitution Operator
Perl | Regex Cheat Sheet