I generally don't like backticks anymore. They are good for a beginner to get started, and they are a quick fix. But in general, I think they are a bad thing now.
I think the most common uses of backticks that I've seen are:
$currDir = `pwd`; chomp $currDir;
@allFiles = `find .`; chomp @allFiles;
system.
$newDir = 'one/two/three/four'; system "mkdir -p $newDir";
Nowadays, I find these to be sloppy practice. In the standard libraries, you are now provided with better ways to do these.
My main complaint is that these are not necessarily portable across platforms, and for that matter might not even be portable across machines across the same platform. Also, you may needlessly be opening shells.
The really quick way to get the current directory is:
$currDir = `pwd`; chomp $currDir;but I think the better way to do it now is:
1 #!/bin/sh
2 #! -*- perl -*-
3 eval 'exec $PERLLOCATION/bin/perl -x $0 ${1+"$@"} ;'
4 if 0;
5
6 use Cwd;
7 $currWorkDir = &Cwd::cwd();
Listing 4.1.1 for code_untested/useCwd.pl
It's still pretty simple, and it's more portable.
Start again with the quickie sloppy way:
@allFiles = `find .`; chomp @allFiles;
This one is actually directly in "Programming Perl" [WALL00] in the modules section for File::Find. I also wind up refering to Perl in a Nutshell [SIEV99] a lot when I work with the standard modules.
1 #!/bin/sh
2 #! -*- perl -*-
3 eval 'exec $PERLLOCATION/bin/perl -x $0 ${1+"$@"} ;'
4 if 0;
5
6 use File::Find;
7 @allFiles = ();
8 &File::Find::find( sub {push @allFiles, $_;}, ".");
Listing 4.1.2 for code_untested/useFileFind.pl
Okay, you might not be too happy about that one. The idea here is that you get the list of files in allFiles, and then after this, you will be doing something to this list of files.
Just a not-so-interesting side note: Our use of @allFiles in this subroutine is technically called a "closure". Even though allFiles is not truly within the scope of the anonymous sub, we're using the anonymous sub to affect its value. Since the sub is defined within the same scope that @allFiles is defined in, the version of allFiles taken inside the anonymous sub is actually the one we want.
Anyway, this is not really the way the Find::file::find routine should be used. Instead of building a list first, and then operating on it, you should operate within the subroutine. Suppose we wanted to do the following:
Look at all the files in the current directory and change anything with the basename of "elementTake57a_inertia" into the basename of "final".
By the way, I think is bad practice to take out the version number from a file name, but just about every production is going to do this... One way you may do this is:
1 #!/bin/sh
2 #! -*- perl -*-
3 eval 'exec $PERLLOCATION/bin/perl -x $0 ${1+"$@"} ;'
4 if 0;
5
6 use File::Find;
7
8 # run this program and give it the arg elementTake57a_inertia
9 $finalBasename = $ARGV[0];
10 @allFiles = ();
11 &File::Find::find( sub {push @allFiles, $File::Find::name;}, ".");
12 foreach my $file (@allFiles) {
13 my($dir, $basename, $frame, $ext) =
14 $file =~ /(.*)\/ # directory up to last slash
15 ([^\/]*) # basename - non-slash chars
16 \. # literal dot
17 (\d+) # frame number - digits
18 \.(\w+)$/x; # extention - ends w/ letters+numbers
19 if ($basename eq $finalBasename) {
20 rename($file, ($dir . '/final.' . $frame . '.' . $ext));
21 }
22
23 }
Listing 4.1.3 for code_untested/designateFinal-1.pl
Not my proudest moment of coding, and there are a ton of things wrong. But I'm just going to address the 'find' issue. The above code could be rewritten to completely skip the "allFiles" array:
1 #!/bin/sh
2 #! -*- perl -*-
3 eval 'exec $PERLLOCATION/bin/perl -x $0 ${1+"$@"} ;'
4 if 0;
5
6 use File::Find;
7
8 # Run this program and give it the arg elementTake57a_inertia
9 $finalBasename = $ARGV[0];
10 &File::Find::find(
11 sub {
12 my($basename, $frame, $ext) = $_ =~
13 /([^\/]*) # basename - non-slash chars
14 \. # literal dot
15 (\d+) # frame number - digits
16 \.(\w+)$/x; # extention - ends w/ letters+numbers
17 my $dir = $File::Find::dir;
18 if ($basename eq $finalBasename) {
19 rename($File::Find::name,
20 ($dir . '/final.' . $frame . '.' . $ext));
21 }
22 }, ".");
Listing 4.1.4 for code_untested/designateFinal.pl
File::Find is very cool module. It's a very good replacement for find, and it's actually very powerful. I generally don't like the imposition of coding styles, but this is actually pretty good.
Actually, in this case, I would make it a little more general, so that it is a general renaming script.
1 #!/bin/sh
2 #! -*- perl -*-
3 eval 'exec $PERLLOCATION/bin/perl -x $0 ${1+"$@"} ;'
4 if 0;
5
6 use File::Find;
7
8 # Run this program and give it the args elementTake57a_inertia final
9
10 ($oldBasename, $newBasename) = @ARGV;
11 &File::Find::find(
12 sub {
13 my($basename, $frame, $ext) = $_ =~
14 /([^\/]*) # basename - non-slash chars
15 \. # literal dot
16 (\d+) # frame number - digits
17 \.(\w+)$/x; # extention - ends w/ letters+numbers
18 my $dir = $File::Find::dir;
19 if ($basename eq $oldBasename) {
20 rename($File::Find::name,
21 ($dir . '/' .$newBaseName.'.'.$frame . '.' . $ext));
22 }
23 }, ".");
Listing 4.1.5 for code_untested/newBaseName.pl
Let's start with the sloppy way again. Supposing you're about to run MTOR and you set the display name to "take001/myBasename." Now, one of the things you need to be aware of in MTOR is that it won't create directories for you. That is, you will initially get "rib," "rmantex," "rmanpix," and a couple others. But with the display name of "take001/myBasename," it will expect to drop RIBs into the directory "rib/take001/" with the basename "myBasename." However, you still need to create that directory yourself, or MTOR will just die.
$newDir = 'rib/take001'; system "mkdir -p $newDir";
You probably want a better way to get the $newDir, assembling it out of some other pieces. But the real thing we're addressing here is the mkdir.
1 #!/bin/sh
2 #! -*- perl -*-
3 eval 'exec $PERLLOCATION/bin/perl -x $0 ${1+"$@"} ;'
4 if 0;
5
6 use Cwd;
7 use File::Path;
8
9 $currWorkDir = &Cwd::cwd();
10 $newDir = 'rib/take001';
11 $fullPath = $currWorkDir . '/' . $newDir;
12 &File::Path::mkpath($fullPath);
Listing 4.1.6 for code_untested/useFilePath.pl
I can't remember if you are required to have a full path or not, so I just created one to be safe. But this is a good, safe way of creating a path in a portable way.