Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!sdd.hp.com!elroy.jpl.nasa.gov!jpl-devvax!lwall From: lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) Newsgroups: comp.lang.perl Subject: find2perl Message-ID: <11674@jpl-devvax.JPL.NASA.GOV> Date: 4 Mar 91 22:47:03 GMT Reply-To: lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) Organization: Jet Propulsion Laboratory, Pasadena, CA Lines: 358 This is an alpha version of find2perl. It spits out a perl script that does the same thing (hopefully) as the corresponding find command. Usage: find2perl . -name '*.bak' -print | perl This isn't thoroughly tested. It does do -print0 and -eval. It doesn't do -ls or -cpio (yet). It does try pretty hard to avoid unnecessary stats. (There ought to be a switch that spits out a package instead of a program, but that's not done yet either. All you need to do is slap a package declaration on the front and avoid calling &dodirs when the package is required. Well, actually, only the &wanted subroutine really needs to be in the package--the others could be global...) Feel free to play with it and/or send/post any additions or comments. Larry #!/bin/sh : make a subdirectory, cd to it, and run this through sh. echo 'If this kit is complete, "End of kit" will echo at the end' echo Extracting find2perl sed >find2perl <<'!STUFFY!FUNK!' -e 's/X//' X#!/usr/bin/perl X Xwhile ($ARGV[0] =~ /^[^-(]/) { X push(@roots, shift); X} Xfor (@roots) { $_ = "e($_); } X$roots = join(',', @roots); X X$indent = 1; X Xwhile (@ARGV) { X $_ = shift; X if ($_ eq '(') { X $out .= &tab . "(\n"; X $indent++; X next; X } X elsif ($_ eq ')') { X $indent--; X $out .= &tab . ")"; X } X elsif ($_ eq '!') { X $out .= &tab . "!"; X next; X } X else { X s/^-// || die "Unrecognized switch: $_\n"; X } X if ($_ eq 'name') { X $out .= &tab; X $pat = shift; X $pat = "*$pat*" unless $pat =~ tr/?*[//; X $pat = &fileglob_to_re($pat); X $out .= '/' . $pat . "/"; X } X elsif ($_ eq 'perm') { X $onum = shift; X die "Malformed -perm argument: $onum\n" unless $onum =~ /^-?[0-7]+$/; X if ($onum =~ s/^-//) { X $onum = '0' . sprintf("%o", oct($onum) & 017777); # s/b 07777 ? X $out .= &tab . "(\$mode & $onum) == $onum"; X } X else { X $onum = '0' . $onum unless $onum =~ /^0/; X $out .= &tab . "(\$mode & 0777) == $onum"; X } X } X elsif ($_ eq 'type') { X ($filetest = shift) =~ tr/s/S/; X $out .= &tab . "-$filetest _"; X } X elsif ($_ eq 'print') { X $out .= &tab . 'print("$dir/$_\n")'; X } X elsif ($_ eq 'print0') { X $out .= &tab . 'print("$dir/$_\0")'; X } X elsif ($_ eq 'fstype') { X $out .= &tab; X $type = shift; X if ($type eq 'nfs') X { $out .= '$dev < 0'; } X else X { $out .= '$dev >= 0'; } X } X elsif ($_ eq 'user') { X $uname = shift; X $out .= &tab . "\$uid == \$uid{'$uname'}"; X $inituser++; X } X elsif ($_ eq 'group') { X $gname = shift; X $out .= &tab . "\$gid == \$gid('$gname')"; X $initgroup++; X } X elsif ($_ eq 'nouser') { X $out .= &tab . '!defined $uid{$uid}'; X $inituser++; X } X elsif ($_ eq 'nogroup') { X $out .= &tab . '!defined $gid{$gid}'; X $initgroup++; X } X elsif ($_ eq 'links') { X $out .= &tab . '$nlink ' . &n(shift); X } X elsif ($_ eq 'inum') { X $out .= &tab . '$ino ' . &n(shift); X } X elsif ($_ eq 'size') { X $out .= &tab . 'int((-s _ + 511) / 512) ' . &n(shift); X } X elsif ($_ eq 'atime') { X $out .= &tab . 'int(-A _) ' . &n(shift); X } X elsif ($_ eq 'mtime') { X $out .= &tab . 'int(-M _) ' . &n(shift); X } X elsif ($_ eq 'ctime') { X $out .= &tab . 'int(-C _) ' . &n(shift); X } X elsif ($_ eq 'exec') { X for (@cmd = (); @ARGV && $ARGV[0] ne ';'; push(@cmd,shift)) { } X shift; X for (@cmd) { s/'/\\'/g; } X $" = "','"; X $out .= &tab . "&exec(0, '@cmd')"; X $" = ' '; X $initexec++; X } X elsif ($_ eq 'ok') { X for (@cmd = (); @ARGV && $ARGV[0] ne ';'; push(@cmd,shift)) { } X shift; X for (@cmd) { s/'/\\'/g; } X $" = "','"; X $out .= &tab . "&exec(1, '@cmd')"; X $" = ' '; X $initexec++; X } X elsif ($_ eq 'prune') { X $out .= &tab . '($prune = 1)'; X } X elsif ($_ eq 'xdev') { X $out .= &tab . '(($prune |= ($dev != $topdev)),1)'; X } X elsif ($_ eq 'newer') { X $out .= &tab; X $file = shift; X $newername = 'AGE_OF' . $file; X $newername =~ s/[^\w]/_/g; X $newername = '$' . $newername; X $out .= "-M _ < $newername"; X $initnewer .= "$newername = -M " . "e($file) . ";\n"; X } X elsif ($_ eq 'eval') { X $prog = "e(shift); X $out .= &tab . "eval $prog"; X } X elsif ($_ eq 'cpio') { X die "-cpio not implemented\n"; X } X elsif ($_ eq 'ls') { X die "-ls not implemented\n"; X } X else { X die "Unrecognized switch: -$_\n"; X } X if (@ARGV) { X if ($ARGV[0] eq '-o') { X $out .= " ||\n"; X shift; X } X else { X $out .= " &&" unless $ARGV[0] eq ')'; X $out .= "\n"; X shift if $ARGV[0] eq '-a'; X } X } X} X Xprint <<'END'; X#!/usr/bin/perl X XEND X Xif ($inituser) { X print <<'END'; Xwhile (($name, $pw, $uid) = getpwent) { $uid{$name} = $uid{$uid} = $uid; } X XEND X} X Xif ($initgroup) { X print <<'END'; Xwhile (($name, $pw, $gid) = getgrent) { $gid{$name} = $gid{$gid} = $gid; } X XEND X} X Xprint $initnewer, "\n" if $initnewer; X Xprint <<"END"; X# Traverse desired filesystems X X&dodirs($roots); X Xexit; X Xsub wanted { X$out; X} X XEND X Xprint <<'END'; Xsub dodirs { X chop($cwd = `pwd`); X foreach $topdir (@_) { X ($topdev,$topino,$topmode,$topnlink) = stat($topdir) X || (warn("Can't stat $topdir: $!\n"), next); X if (-d _) { X if (chdir($topdir)) { X $topdir = '' if $topdir eq '/'; X &dodir($topdir,$topnlink); X } X else { X warn "Can't cd to $topdir: $!\n"; X } X } X else { X unless (($dir,$_) = $topdir =~ m#^(.*/)(.*)$#) { X ($dir,$_) = ('.', $topdir); X } X chdir $dir && &wanted; X } X chdir $cwd; X } X} X Xsub dodir { X local($dir,$nlink) = @_; X local($dev,$ino,$mode,$subcount); X X # Get the list of files in the current directory. X X opendir(DIR,'.') || die "Can't open $dir"; X local(@filenames) = readdir(DIR); X closedir(DIR); X X if ($nlink == 2) { # This dir has no subdirectories. X for (@filenames) { X next if $_ eq '.'; X next if $_ eq '..'; X &wanted; X } X } X else { # This dir has subdirectories. X $subcount = $nlink - 2; X for (@filenames) { X next if $_ eq '.'; X next if $_ eq '..'; X $nlink = $prune = 0; X &wanted; X next if $subcount == 0; # Seen all the subdirs? X X # Get link count and check for directoriness. X X ($dev,$ino,$mode,$nlink) = lstat($_) unless $nlink; X next unless -d _; X next if $prune; X X # It really is a directory, so do it recursively. X X if (chdir $_) { X &dodir("$dir/$_",$nlink); X chdir '..'; X } X --$subcount; X } X } X} X XEND X Xif ($initexec) { X print <<'END'; Xsub exec { X local($ok, @cmd) = @_; X foreach $word (@cmd) { X $word =~ s#{}#$dir/$_#g; X } X if ($ok) { X local($old) = select(STDOUT); X $| = 1; X print "@cmd"; X select($old); X return 0 unless =~ /^y/; X } X chdir $cwd; # sigh X system @cmd; X chdir $dir; X return !$?; X} X XEND X} X Xexit; X X############################################################################ X Xsub tab { X local($tabstring); X X $tabstring = "\t" x ($indent / 2) . ' ' x ($indent % 2 * 4); X if ($_ !~ /^(name|print)/) { X if (!$statdone) { X $tabstring .= <<'ENDOFSTAT' . $tabstring; X(($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && XENDOFSTAT X $statdone = 1; X } X } X $tabstring =~ s/^\s+/ / if $out =~ /!$/; X $tabstring; X} X Xsub fileglob_to_re { X local($tmp) = @_; X X $tmp =~ s/([.^\$()])/\\$1/g; X $tmp =~ s/([?*])/.$1/g; X "^$tmp$"; X} X Xsub n { X local($n) = @_; X X $n =~ s/^-0*/< / || $n =~ s/^\+0*/> / || $n =~ s/^0*/== /; X $n; X} X Xsub quote { X local($string) = @_; X $string =~ s/'/\\'/; X "'$string'"; X} !STUFFY!FUNK! echo "" echo "End of kit" : I do not append .signature, but someone might mail this. exit