A couple of suggestions for your code:
- Although it works, open(IN, ,"<", $file) has an extra comma in it. Also lexical filehandles are generally considered to be better (e.g. open my $in, '<', $file or die $!;)
- You use the array @_ in your subs for storing data. While that's possible, @_ is generally only used to access the arguments passed into a sub, and using it the way you're doing is very likely to confuse others working with your code.
- Although I'm not sure what your intentions were, I suspect the regex /Date of Last Update:+/ is not doing what you expect: It'll match the string "Date of Last Update" followed by one or more colons. If you want to match the string itself multiple times, you need a group: /(?:Date of Last Update:)+/, although I'm not sure if the input file will ever contain the string "Date of Last Update:Date of Last Update:". Also, {1,} is equivalent to +.
- You can use your variable $substr in your regular expressions, e.g. /\Q$substr\E/ (for the meaning of \Q...\E see quotemeta).
- Naming a sub the same as a Perl keyword, in this case "grep", is generally a bad idea - the only exception is when you're actually trying to replace the built-in grep - because it will create much confusion as to which function is supposed to be called when, both for the readers of your code and for Perl. This confusion is why you had to call your "grep" as &grep();. Also, inside your "grep", you're calling Perl's grep, any slight mistake in syntax may call your "grep" instead and create infinite recursion.
- A small hint: grep { $_ =~ /Date of Last Update:/ } can be written as grep { /Date of Last Update:/ } and "... file: ".$file.": $!\n"; can be written as "... file: $file: $!\n";
- On style: If you find yourself using $_ a lot, over multiple lines, then usually it's better to use a lexical variable instead. $_ is global and can (accidentally) be manipulated by other code, especially code that someone else inserts later. You can use something like while (my $line = <$in>) { instead.