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.