The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

pfind - A Perl based find replacement

SYNOPSIS

  pfind dir1 dir2 ... [--exec perl_code]

The program recursively crawls through all the directories listed on its command line and execute some piece of perl code on each files and directories that are encountered.

DESCRIPTION

pfind is a replacement for the standard find command where the countless flags and options are mostly all replaced by a single option (--exec) that can execute arbitrary Perl code.

See examples of pfind in action below, in the "EXAMPLES" section.

OPTIONS

All the options below can be abbreviated down to uniqueness and be supplied in any order. Input files and directories can be mixed in with the options. Options processing can be stopped with the -- flag, all remaining arguments will be considered input files.

-e code, --exec

Execute the given piece of code for each file and directory encountered by the program. The program will chdir into each directory being crawled before calling your code and the $_ variable will contain the base name of the current file or directory. In addition, the $dir variable will contain the directory name of the current file and $name will contain the full name of the file (more or less $dir concatenated with $_).

The code can also call the prune method to skip recursing into the current directory. This has no effect if called while looking at a file. This cannot be used if the --depth-first option is passed. This does not interupt the execution of the code for the current directory or file.

You will typically uses the code to perform tests on the given file and some sort of actions depending on the result of the tests. See "EXAMPLES" below.

This option can be passed multiple times. However, multiple pieces of code given to this option will not be independant: they will share the same variables and if return is called by a piece of code, no more code will be executed for the current file. However the keyword next can be used to jump to the next piece of code to be executed.

One exception is that the $_, $dir, and $name variables are saved and each piece of coce will initially see the correct values. The variables can be modified but the next pieces of code executed after the current one will not see the modification.

-d, --depth-first

When this option is passed, the code given to --exec will be called first for the content of a directory and then for the directory itself (this is a depth first approach). By default, the code is executed first for a directory and then for its content.

Using this option might be required if you're planning on changing the name of a directory.

The opposite option is --no-depth-first (or --nod).

-t types, --type

Filter the files on which the actions should be executed. This argument can receive a list of characters defining type of files to accept. There should be no separators. Alternatively the option can be passed multiple times.

Valid values for types: f, a regular file; d, a directory; l, a symbolic link; b, a block special file; c, a character special file; p, a fifo file (pipe); s, a socket.

Note that these types are not mutually exclusive. If multiple types are passed, only files that match all the types will be accepted. A type can be given in upper-case to reverse its meaning (excluding the files of that type).

When a file is filtered, the code given to --exec will not be executed for that file but, if this file is a directory, the --pre and --post code will still execute. Filtering directories will also not prevent from recursing in them (you can use the --no-recurse option for that).

-f, --follow

When this option is passed, symlinks are followed (by default they are treated as files but not followed).

-ff, --follow-fast

Same as --follow but faster. However, with this option, it is possible that some files will be processed twice if the symlinks for some kind of cycles.

The --follow and --follow-fast options are mutually exclusive.

--chdir

When this option is set (which is the default), the program will chdir into each directory being crawled before calling your code.

This behavior can be deactivated with the opposite option --no-chdir. In this case, during the execution of the code passed to --exec, the $_ variable will contain the full path to the current file (same as the $name variable). That name will be absolute or relative, depending on whether the starting directory given on the command line has been given with an absolute or relative path.

-p text, --print

Print the argument of this function after each call of the Perl print function. This defaults to a new-line. Technically this option is setting the $\ variable in Perl.

--no-recurse, -nor

Do not recurse into directories given on the command line. These directories are still processed like normal files but not their content.

This option cannot be used when --depth-first is passed.

-B code, --BEGIN

Specify a piece of code that is executed before starting to crawl the directories. That code can set-up variables and functions to be used later by the code passed to --exec.

This option can be passed several times. Each piece of code will be called in order.

-E code, --END

Similar to the --BEGIN option, but the passed code will be executed after all the crawling is done.

--pre code, --pre-process

Execute the given piece of code each time a directory is entered. The name of the current directory is in the variables $_ and $dir. If --chdir is in effect (the default), then the current directory is already set to that directory.

This option cannot be used together with --follow or --follow-fast.

Note: the matching option in the underlying File::Find Perl library support modifying which files of the directory will be used. This is not supported by pfind.

--post code, --post-process

Execute the given piece of code just before exiting each processed directory. The name of the (still) current directory is in the variables $_ and $dir. If --chdir is in effect (the default), then the current directory is still set to that directory.

This option cannot be used together with --follow or --follow-fast.

-h, --help

Print this help message and exits. Note: the help message printed will be much improved if you have the perldoc program installed (sometimes from a perl-doc package).

-v, --verbose

Print the version of the program and exit.

--version

Print the version of the program and exit.

PERL ENVIRONMENT

In addition to the variables listed above ($_, $name, and $dir), the Perl environment used to execute the code provided to the --exec, --BEGIN, --END, --pre, and --post flags will contain the following methods.

cp and mv

These methods (coming from the File::Copy module) both takes two arguments (two file names) and copy or move the first file to the second one (in the case of mv, the second argument can also be a directory name, that must already exists).

mkdir and rmdir

These two functions exist by default in Perl (mkdir and rmdir) but improved versions that can take more than one arguments are provided.

If no arguments are passed, use $_.

rm

This function takes a list of files and directories and delete them. While it is built on top of the remove_tree function from File::Path, it will only delete files or empty directories and will recurse in non-empty directories.

If no arguments are passed, use $_.

rmtree

An alias to the standand remove_tree function from File::Path. This takes a lis of files or directories and delete them all recursively. Use with caution!

If no arguments are passed, use $_.

EXAMPLES

A default invocation of the program without arguments other than directories and files will as the find program, printing the recursive content of all the listed directories and files:

  pfind dir1 dir2 dir3

By default, pfind chdir into each directory, so the only the base name of the files is printed. With the --no-chdir option, the full name of the files is printed:

  pfind --no-chdir dir1 dir2 dir3

This example will print the name of all the files and directories that it sees but it will skip the content of hidden directories and hidden directories themselves:

  pfind -e 'if (/^\..+/) { prune; return }' -e 'print $name' dir...

This example prints the name of all symbolic links whose targets are invalid:

  pfind -e 'print $name if -l && !-e'

Using the --type option, the same example could be written:

  pfind -t l -e 'print $name unless -e'

Rename all the file in the current folder, replacing _ by - but do not recurse into sub-directories:

  pfind -e '$r = s/_/-/gr; system "mv \"$_\" \"$r\""' -e 'prune unless /\./' .

Print the name of all the folders that don't contain a particular file called somefile.ext:

  pfind -e '$a{$dir}++ if /somefile.ext/' -pre '$a{$_} = 0' \
        -post 'print unless $a{$_}' .

AUTHOR

This program has been written by Mathias Kende.

LICENCE

Copyright 2019 Mathias Kende

This program is distributed under the MIT (X11) License: http://www.opensource.org/licenses/mit-license.php

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

SEE ALSO

perl(1), find(1), xargs(1), File::Find