On Thu, 28 Mar 2002 12:17:28 +0800, allan wrote:

>hello
>
>i need to detab a bunch of files in a bunch of directories.
>
>this script:
>
>#!/usr/bin/perl -pi
>s/\t/    /;
>
>
>will do what i want when a supply the files as arguments
>from the commandline.

Wow, hold it. If you use something that simple, you'll likely end up
with some weird looking text (source?) files.

You seem to want tab positions every 4 columns. Now, somebody will
likely suggest using some module for that, but here is some handcrafted
code:

        s/(.*?)\t/$1.(' ' x (4-length($1)%4))/ge;

It will take into account the length of the string before the tab
starting from the start of the string, from the previous newline, or
from the last replaced tab; and pad with 1 to 4 spaces so the string
length becomes the next multiple of 4.

It seems to work fine for me.

>i have a script that traverse all directories from a
>specfied starting point.
>so when i recursively get to a new file i wish to detab that
>file on the fly as if i had supplied the filename as an argument
>
>sub recursion {
>  ...
>  if (-f $specfile ) {
>    # detab code goes here
>  }
>  ...
>  # next file/dir
>}
>
>
>is that possible still using the -i switch?

My first thought would be to have two scripts, and call the other script
with

        system($^X, "-pi", "detab.pl", $_);

$^X is the full path of the perl executable.

But, then, of course, your platform should support calling external perl
scripts this way. I think that this will be problematic on a Mac, most
of all if you don't have ToolServer installed (IIRC).

Also note that some platforms do require that you provide an extension
for the -i command line switch. (Windows, Mac ?) You'll get a backup
file that way, I know...

BTW instead of calling an external script, you ougth to be able to use
the -e command line option.
A second approach would be to have just one script, fill @ARGV in a
BEGIN block. Yeah, that looks like it would be the best approach.

        #!/usr/bin/perl -pi
        BEGIN {
             use File::Find;
             use Cwd;
             my @argv = @ARGV; @ARGV = ();
             find sub {
                 push @ARGV, $File::Find::name if -f and /\.txt$/;
             }, @argv ? @argv : cwd;
        }

        s/(.*?)\t/$1.(' ' x (4-length($1)%4))/ge;

UNTESTED!

The idea is that you pass the path of the root directory(/-ies) on the
command line, or it will pick the current working directory without
arguments. It will fill @ARGV with a complete list of all found files.
BTW any plain files in the command arguments get included too, if they
match the pattern. That's a feature of File::Find.

It does that in a BEGIN block, so this is run once, at the start of your
script. The main body of the script is run using the -pi command line
switches, so that part runs once for every line in the input files.

   HTH,
   Bart.

Reply via email to