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

Hi ,
I am a pretty intermittent user of perl , i am trying to
write a subroutine to search for a pattern in a file , which
i will call multiple times based on the need. But i seem to
have made some mistake as the script just gets stuck.
Can i please get some pointers on how to proceed
&find_pattern($dir1); sub find_pattern { my $file3="/etc/filesystems"; my $pattern = $_; my $result = `grep $pattern $file3`; if ($result) { print "Entry for $pattern is updated in $file3/n!"; } else { print "Entry for $pattern not found in $file3/n!"; } return; }

Replies are listed 'Best First'.
Re: subroutine to search a pattern in a file
by Anonymous Monk on Apr 12, 2010 at 10:29 UTC
Re: subroutine to search a pattern in a file
by tospo (Hermit) on Apr 12, 2010 at 12:38 UTC

    I would also suggest to pass the path to the file as an argument. You can always define a default as a constant in the top of your script where it is easy to find and change if needed. That's more maintainable than hardcoding a path in a subroutine

    use constant DEFAULT_FILE => "/etc/filesystems"; my $file = shift || DEFAULT_FILE; # e.g. to take file from command lin +e or use the default find_pattern($file, $pattern); sub find_pattern { my ($file, $pattern) = @_; # your code here }

    Another general advise would be to separate the test and the action. Ideally, a subroutine "find_pattern" should return true if it found it and false if it didn't. For example next time you might want to terminate a script rather than print to STDOUT:

    ... die "oh no, it's not there!" unless find_pattern($file, $pattern); sub find_pattern { my ($file, $pattern) = @_; return `grep $pattern $file`; }
Re: subroutine to search a pattern in a file
by Marshall (Canon) on Apr 13, 2010 at 05:24 UTC
    I ran through some various scenarios for you on a Linux machine...see below. To get the results of a "backtick, `" command, normally you should use an "@" variable when multiple lines could happen. In Perl when you assign an array to a scalar like: $number = @array, $number is the number of things in @array. So: "if (@array){}" gives you a way to test whether or not something is in the @array or not.

    Also, as a general rule: if a subroutine opens a file, it should be responsible for closing it. A subroutine shouldn't leave a file open when it returns. Explicit closes are not required in the main program as all open file handles are closed when the main program exits. But if you pass a file name to something like my find_matching_lines() subroutine, you should close that file when you are finished with it, otherwise open the file the main program and pass a filehandle to the subroutine.

    #!/usr/bin/perl -w use strict; print "*the backtick cat results:*\n"; print `cat /etc/filesystems`; #prints: # ext3 # ext2 # nodev proc # nodev devpts # iso9660 # vfat # hfs # hfsplus print "\n"; #spacer line my @catlines = `cat /etc/filesystems`; print "*the catlines array:*\n"; print @catlines; #prints same as backtick results above print "\n"; #spacer line my $file = '/etc/filesystems'; my $pattern = 'nodev'; my @lines= `grep $pattern $file`; print "*the grep backtick results:*\n"; print @lines; print "\n"; #spacer line #prints: # nodev proc # nodev devpts my @getlines = find_matching_lines($file,'ext'); print "*the getlines array*\n"; print scalar(@getlines), " lines found\n"; my $numlines = @getlines; print "number of lines = $numlines\n"; #same thing print "".@lines," lines found\n"; #the concatentation op "." forces sc +alar print @getlines; sub find_matching_lines { my ($file_name, $pattern)=@_; my @matches =(); open (my $in, '<', $file_name) or die "unable to open $file_name"; while (<$in>) { push (@matches,$_) if m/$pattern/; } close ($in); return @matches; } __END__ *the backtick cat results:* ext3 ext2 nodev proc nodev devpts iso9660 vfat hfs hfsplus *the catlines array:* ext3 ext2 nodev proc nodev devpts iso9660 vfat hfs hfsplus *the grep backtick results:* nodev proc nodev devpts *the getlines array* 2 lines found number of lines = 2 2 lines found ext3 ext2