OK, the hints shown at the bottom worked pretty well for me. I wanted to find a certain string in C source files, but not be distracted by compiled release directories named "rel*". I guessed at which wildcard syntax ack supports, and I think I won:
YMMV. No warranties expressed or implied. Thank god for undocumented/lightly documented features... ;-)
Cheers,
Connie
----------------------------------------
Stack Overflow:
"
How do I ignore specific directories via RegEx with ack?
I can use the --ignore-dir option, but this does not let me specify a RegEx. I want to be able to ignore any directory, which has the words test or tests or more complicated patterns in its name.
I also tried a negative lookbehind via
ack -G '(? pattern
but this does not work. It does not exclude the test directories.
If you want to pass this handler to a perl function, you would use typeglob as shown below.
#!/usr/bin/perl
open FH,";
print @lines;
}
2. Opening a Perl File Handle reference in Normal Scalar Variable
You can use a scalar variables to store the file handle reference as shown below.
#!/usr/bin/perl
# $log_fh declared to store the file handle.
my $log_fh;
open $log_fh,";
print @lines;
}
3. Use Perl IO::File to Open a File Handle
IO::File is a perl standard CPAN module which is used for opening a file handle in other colourful conventions. Use cpan command to install perl modules.
#!/usr/bin/perl
use IO::File;
$read_fh = IO::File->new("/tmp/msg",'r');
read_text($read_fh);
sub read_text
{
local $read_fh = shift;
my @lines;
@lines = <$read_fh>;
print @lines;
}
Following perl code snippet explains perl write operation with IO::File module.
$write_fh = IO::File->new("/tmp/msg",'w');
To open the file handler in append mode, do the following.
4. Open Perl File Handler in Both Read and Write mode
When you want to open both in read and write mode, Perl allows you to do it. The below perl mode symbols are used to open the file handle in respective modes.
MODE
DESCRIPTION
+<
READ,WRITE
+>
READ,WRITE,TRUNCATE,CREATE
+>>
READ,WRITE,CREATE,APPEND
Let us write an example perl program to open a sample text file in both read and write mode.
$ cat /tmp/text
one
two
three
four
five
The below code reads first line from the /tmp/text file and immediately does the write operation.
#!/usr/bin/perl
open(FH,"+;
print $line;
}
sub write_line
{
local *FH = shift;
print FH @_;
}
close(FH);
The output of the above code is shown below.
$ perl ./read_and_write.pl
one
$ cat /tmp/text
one
222
three
four
five
Different types of modes are shown in the table below.
MODE
DESCRIPTION
O_RDONLY
READ
O_WRONLY
WRITE
O_RDWR
READ and WRITE
O_CREAT
CREATE
O_APPEND
APPEND
O_TRUNC
TRUNCATE
O_NONBLOCK
NON BLOCK MODE
Note : You would need to have the habit of validating opened file handlers. The most common way of handling the file handler open failure with the die function is shown below.
open(FH,">/tmp/text") or die "Could not open /tmp/text file : $!\n";
If the above code is unable to open the file “/tmp/text”, it returns failure, and die gets executed. And the “$!” Buildin variable contains the reason for open function failure.
Perl FAQ: How do I read command-line arguments in Perl (i.e., "Perl command line args")?
If you want to handle simple Perl command line arguments, such as filenames and strings, this tutorial is for you. If you want to handle command-line options (flags) in your Perl scripts (like "-h" or "--help"), this new Perl getopts command line options/flags tutorial is what you need.
Perl command line args and the @ARGV array
With Perl, command-line arguments are stored in a special array named @ARGV. So you just need to read from that array to access your script's command-line arguments.
ARGV array elements: In the ARGV array, $ARGV[0] contains the first argument,$ARGV[1] contains the second argument, etc. So if you're just looking for one command line argument you can test for $ARGV[0], and if you're looking for two you can also test for $ARGV[1], and so on.
ARGV array size: The variable $#ARGV is the subscript of the last element of the @ARGVarray, and because the array is zero-based, the number of arguments given on the command line is $#ARGV + 1.
Example 1: A typical Perl command line args example
A typical Perl script that uses command-line arguments will (a) test for the number of command line arguments the user supplied and then (b) attempt to use them. Here's a simple Perl script named "name.pl" that expects to see two command-line arguments, a person's first name and last name, and then prints them:
#!/usr/bin/perl -w
# (1) quit unless we have the correct number of command-line args
$num_args = $#ARGV + 1;
if ($num_args != 2) {
print "\nUsage: name.pl first_name last_name\n";
exit;
}
# (2) we got two command line args, so assume they are the
# first name and last name
$first_name=$ARGV[0];
$last_name=$ARGV[1];
print "Hello, $first_name $last_name\n";
This is fairly straightforward, where adding 1 to $#ARGV strikes me as the only really unusual thing.
To test this script on a Unix/Linux system, just create a file named name.pl, then issue this command to make the script executable:
chmod +x name.pl
Then run the script like this:
./name.pl Alvin Alexander
Or, if you want to see the usage statement, run the script without any command line arguments, like this:
./name.pl
Example 2: Perl command line arguments in a for loop
For a second example, here's how you might work through the command line arguments using a Perl for loop:
#!/usr/bin/perl
#---------------------#
# PROGRAM: argv.pl #
#---------------------#
$numArgs = $#ARGV + 1;
print "thanks, you gave me $numArgs command-line arguments:\n";
foreach $argnum (0 .. $#ARGV) {
print "$ARGV[$argnum]\n";
}
Running the example Perl command line program
To demonstrate how this works, if you run this Perl command line args program from a Unix command-line like this:
./argv.pl 1 2 3 4
or, from a DOS command-line like this
perl argv.pl 1 2 3 4
you'll get this result:
thanks, you gave me 4 command-line arguments:
1
2
3
4
As you can see, it prints all the command line arguments you supply to the Perl program.
When a Perl script is run, its command-line arguments (if any) are stored in an automatic array called @ARGV. You'll learn how to manipulate this array later. For now, just know that you can call the shift function repeatedly from the main part of the script to retrieve the command line arguments one by one.
Printing the Command Line Argument
Code:
#!/usr/bin/perl
# file: echo.pl
$argument = shift;
print "The first argument was $argument.\n";
This snippet looks especially interesting. I hadn't tried this before.
"November, 2008: Excuse the interuption, but there is something new to talk about and I didn't want you to have to go all the way to the comments to find it. It's called "ack", it's written in Perl, and it addresses the things the things this page talks about. Find it at http://betterthangrep.com/. "
You must mean that your ancient Unix doesn't have GNU grep, right? If you do, just go do a "man grep"; you don't need to read this (though you may want to just so you really appreciate GNU grep). Just add "-r" (with perhaps --include) and grep will search through subdirectories.
Say you wanted to search for "perl" in only *.html files in the current directory and every subdirectory. You could do :
grep -r --include="*.html" perl .
("." is current directory)
You don't even need the --include; "grep -r perl . " will search all files. If you had a directory strucure like this:
either invocation would search "perlinhere" looking for "perl" inside. So would:
grep -r --include="*.html" perl b*
But this of course would not (because the file with the pattern is not under "a*"):
grep -r --include="*.html" perl a*
You can also use --exclude= to search every file except the ones that match your pattern.
(BSD grep has "-d recurse". That also works in GNU grep and is equivalent to "-r")
Easy enough, isn't it?
But if you are on some old Unix without recursive capabilities in its grep, it gets very hard. The problem with all the reponses that invariably pop up for this type of question is that none of them are ever truly fast and most of them aren't truly robust.
Typically, the answer is to use find, xargs, and grep. That's horribly slow for a full filesystem search, and it's painfully difficult to properly construct a pipeline that will avoid searching binaries if you don't want to, won't get stuck on named pipes or blow up on funky filenames (beginning with -, or sometimes spaces, punctuation etc). There are ways around all these things, but they are all ugly.
BTW, something that almost never gets mentioned but that I will frequently use under conditions where it is appropriate is a simple
grep pattern * */* */*/* 2>/dev/null
Not useful much beyond that, and may not even be good at that except for certain starting points, but it's faster than any find xargs pipeline can ever be if the set is small enough.
That's pretty awful, but it's what you have to get into if you have special cases. Special cases are what makes this question more difficult. If you have a small number of files and subdirs to search, the simple approach may work fine for you. If not, you have to get more creative.
November, 2008: Excuse the interuption, but there is something new to talk about and I didn't want you to have to go all the way to the comments to find it. It's called "ack", it's written in Perl, and it addresses the things the things this page talks about. Find it at http://betterthangrep.com/.
Bill Campbell offers this Perl script:
I have a perlscript I call ``textfiles'' that I use for many
things like this:
textfiles dirname [dirname... ] | xargs ...
Essentially it runs ``gfind @ARGV -type f'', then uses perl's -T
option on each file to determine whether it's a text file.
My textfiles script also has options to add options to the gnu
find command like -xdev, -mindepth, and -maxdepth.
Hell, it's short so I'm attaching it for anybody who wants to use
it. It does assume that the gnu version of find is in your PATH
named gfind (I make a symlink to /usr/bin/find on Linux systems
so that it works there as well).
#!/usr/local/bin/perl
eval ' exec /usr/local/bin/perl -S $0 "$@" '
if $running_under_some_shell;
# $Header: /u/usr/cvs/lbin/textfiles,v 1.7 2000/06/22 18:29:08 bill Exp $
# $Date: 2000/06/22 18:29:08 $
# @(#) $Id: textfiles,v 1.7 2000/06/22 18:29:08 bill Exp $
#
# find text files
( $progname = $0 ) =~ s!.*/!!; # save this very early
$USAGE = "
# Find text files
#
# Usage: $progname [-v] [file [file...]]
#
# Options Argument Description
# -f Follow symlinks
# -M maxdepth maxdepth argument to gfind
# -m mindepth mindepth argument to gfind
# -x Don't cross device boundaries
# -v Verbose
#
";
sub usage {
die join("\n",@_) .
"\n$USAGE\n";
}
do "getopts.pl";
&usage("Invalid Option") unless do Getopts("fM:m:xvV");
$verbose = '-v' if $opt_v;
$suffix = $$ unless $opt_v;
$\ = "\n"; # use newlines as separators.
# use current directory if there aren't any arguments
push(@ARGV, '.') unless defined($ARGV[0]);
$args = join(" ", @ARGV);
$xdev = '-xdev' if $opt_x;
$opt_f = '-follow' if $opt_f;
$opt_m = "-mindepth $opt_m" if $opt_m;
$opt_M = "-maxdepth $opt_M" if $opt_M;
$cmd = "gfind @ARGV -type f $xdev $opt_f $opt_m $opt_M |";
print STDERR "cmd = >$cmd<" if $verbose;
open(INPUT, $cmd);
while() {
chop($name = $_);
print STDERR "testing $name..." if $verbose;
print $name if -T $name;
}
John Dubois also comments on Glimpse:
Glimpse indexes files by the words contained in the file. Then when you want to search all of the files, it only runs its equivalent of grep (agrep) on the files that contain the words you're looking for. You can search for partial words too, though it takes longer. I have the man pages, include files, rfcs, source trees, my home directory, web pages, etc. all separately glimpse-indexed.