Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Why does this script fail? 2

Status
Not open for further replies.

mirage4d

IS-IT--Management
Apr 16, 2007
5
US
Greetings. I'm new to perl, and this should be a simple task, but I am dropping the ball somewhere. I'm working on a script to automate the archiving of some .pdf files nightly. It will be necessary for perl to rename the files that have been copied over; that is where I have hit the wall. My script as it is now will *not* rename the files using scalars. It seems to work fine if the filename is explicity defined in the rename function. Some of the formatting got a little wacky towards the end in the cut/paste, but it should be fairly discernable. The code as it is now reads as:


#!/usr/bin/perl

#Mount appropiate shares
`mount_smbfs //########:####\@192.168.213.50/JobData /Volumes/athripd005`;

#Create list of folders to archive
$folders[0]="/usr/local/tomove";
#$folders[0]="/Volumes/athripd005/Active Lifestyles/Refined PDF/";
#$folders[1]="/Volumes/athripd005/Business Week/Refined PDF/";
#$folders[2]="/Volumes/athripd005/Classic Living/Refined PDF/";
#$folders[3]="/Volumes/athripd005/Early Run/Refined PDF/";
#$folders[4]="/Volumes/athripd005/Gameday/Refined PDF/";
#$folders[5]="/Volumes/athripd005/Classic Living/Refined PDF/";
#$folders[6]="/Volumes/athripd005/Madison-Oconee/Classifieds/Refined PDF/";
#$folders[7]="/Volumes/athripd005/Madison-Oconee/Madison/Refined PDF/";
#$folders[8]="/Volumes/athripd005/Madison-Oconee/Oconee/Refined PDF/";


#Descend into folders and copy appropriate PDFs to desktop folder.
for ($i = 0; $i < @folders; $i++){

chdir $folders[$i];
$pwd=`pwd`;
print("\n$pwd");

@filenames=`ls -1`;

foreach $_ (@filenames){
print("\nFILE: $_");
if (($_ =~m/pdf/ == 1) && ($_ =~ m/archived/ != 1)){
print("\nTHIS IS A NEW PDF");
$archived=$_;
$archived =~ s/pdf/pdfarchived/;
$directory=`pwd`;


`cp $_ /usr/local/moved`;
print "\nrename $_ $archived\n";
rename($_ , $archived) || die "Cannot rename $_ in $directory: $!";
}

}
}


Note that for now I have commented out the specifics of the script and created very basic directories (/usr/local/tomove and /usr/local/moved) in an attempt to get the script to work. This was also to rule out the possibility that it was an issue with trying to use the rename function across filesystems - which the script will eventually need to do. So all this script is trying to do at the moment is match on pdf and copy the file from /usr/local/tomove to /usr/local/moved and rename it...i.e. match blackpdf, cp it to /usr/local/moved, and rename it from blackpdf to blackpdfarchived.

The script fails when using scalars in the rename function with "No such file or directory.", and it does the same thing if I try to use the "mv" command. Obviously, the file is indeed still in present in the directory. If I try to use the File::Copy module, it fails with an error message regarding a newline in the file. However, if I explicity list the filename in all of the above mentioned functions, the script works. The use of the variable seems to be the issue.

I apologize for such a lengthy first post. Anyone have any suggestions here? Hopefully it is a careless mistake on my part. Thanks in advance.
 
what does this print?

print "\nrename $_ $archived\n";

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Each filename output by the ls command is terminated by a newline.

Put a "chomp;" as the first thing you do for each file.

You may also need to trim trailing whitespace.
 

Kevin ADC,

The print statement does indeed print the expected output...the old file and the new appended file.


Brigmar,

I toyed with the chomp statement briefly thinking along the same lines, but abandoned it fairly quickly. I'll go back to it and see what happens.



Thanks for the input guys.

 

Thanks for the fix Brigmar. A combination of chomp/chop did the trick. Very much apprectiated.
 
Hello mirage4d,

It appears that you already fixed your script, but I would advise a few stylistic changes.

[ol]
[li]Stick with pure perl unless there is a specific reason why you need system level operations. Mixing introduces risk on some systems especially working with the "Current Working Directory". That is why there is the Cwd module so you can avoid needing `pwd`.[/li]
[li]Don't bother changing the current working unless you really need to. It's safer to just stick with explicit paths.[/li]
[li]If you ever find yourself explicitly writing out $_, then you should probably be using a real variable name.[/li]
[li]Don't do "$str =~ /regex/ == 1" or "$str =~ /regex/ != 1". Just use "$str =~ /regex/" and "$str != /regex/".[/li]
[li]rename works, but move of the File::Copy module is better. It will first try to simply rename the file, but if that is allowed then it will then do a copy to then new location and then delete the original.[/li]
[/ol]

Here is your script with these changes implemented:

Code:
[gray]#!/usr/bin/perl[/gray]

[url=http://perldoc.perl.org/functions/use.html][black][b]use[/b][/black][/url] [green]File::Copy[/green] [red]qw([/red][purple]copy move[/purple][red])[/red][red];[/red]

[black][b]use[/b][/black] [green]strict[/green][red];[/red]

[gray][i]#Mount appropiate shares[/i][/gray]
[red]`[/red][purple]mount_smbfs //########:####[purple][b]\@[/b][/purple]192.168.213.50/JobData /Volumes/athripd005[/purple][red]`[/red][red];[/red]

[gray][i]#Create list of folders to archive[/i][/gray]
[url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]@folders[/blue] = [red]([/red]
	[red]"[/red][purple]/usr/local/tomove[/purple][red]"[/red],
[gray][i]#	"/Volumes/athripd005/Active Lifestyles/Refined PDF/",[/i][/gray]
[gray][i]#	"/Volumes/athripd005/Business Week/Refined PDF/",[/i][/gray]
[gray][i]#	"/Volumes/athripd005/Classic Living/Refined PDF/",[/i][/gray]
[gray][i]#	"/Volumes/athripd005/Early Run/Refined PDF/",[/i][/gray]
[gray][i]#	"/Volumes/athripd005/Gameday/Refined PDF/",[/i][/gray]
[gray][i]#	"/Volumes/athripd005/Classic Living/Refined PDF/",[/i][/gray]
[gray][i]#	"/Volumes/athripd005/Madison-Oconee/Classifieds/Refined PDF/",[/i][/gray]
[gray][i]#	"/Volumes/athripd005/Madison-Oconee/Madison/Refined PDF/",[/i][/gray]
[gray][i]#	"/Volumes/athripd005/Madison-Oconee/Oconee/Refined PDF/",[/i][/gray]
[red])[/red][red];[/red]


[gray][i]#Descend into folders and copy appropriate PDFs to desktop folder.[/i][/gray]
[olive][b]foreach[/b][/olive] [black][b]my[/b][/black] [blue]$dir[/blue] [red]([/red][blue]@folders[/blue][red])[/red] [red]{[/red]

	[url=http://perldoc.perl.org/functions/opendir.html][black][b]opendir[/b][/black][/url][red]([/red]DIR, [blue]$dir[/blue][red])[/red] or [url=http://perldoc.perl.org/functions/die.html][black][b]die[/b][/black][/url] [red]"[/red][purple]can't opendir [blue]$dir[/blue]: [blue]$![/blue][/purple][red]"[/red][red];[/red]
	[black][b]my[/b][/black] [blue]@filenames[/blue] = [url=http://perldoc.perl.org/functions/grep.html][black][b]grep[/b][/black][/url] [red]{[/red] ![red]/[/red][purple]^[purple][b]\.[/b][/purple]+$[/purple][red]/[/red] [red]}[/red] [url=http://perldoc.perl.org/functions/readdir.html][black][b]readdir[/b][/black][/url][red]([/red]DIR[red])[/red][red];[/red]
	[url=http://perldoc.perl.org/functions/closedir.html][black][b]closedir[/b][/black][/url] DIR[red];[/red]

	[olive][b]foreach[/b][/olive] [black][b]my[/b][/black] [blue]$file[/blue] [red]([/red][blue]@filenames[/blue][red])[/red][red]{[/red]
		[url=http://perldoc.perl.org/functions/print.html][black][b]print[/b][/black][/url] [red]"[/red][purple][purple][b]\n[/b][/purple]FILE: [blue]$file[/blue][/purple][red]"[/red][red];[/red]
		
		[olive][b]if[/b][/olive] [red]([/red][blue]$file[/blue] =~ [red]m/[/red][purple]pdf[/purple][red]/[/red] && [blue]$file[/blue] !~ [red]m/[/red][purple]archived[/purple][red]/[/red][red])[/red] [red]{[/red]
			[black][b]print[/b][/black][red]([/red][red]"[/red][purple][purple][b]\n[/b][/purple]THIS IS A NEW PDF[/purple][red]"[/red][red])[/red][red];[/red]

			[black][b]my[/b][/black] [blue]$archived[/blue] = [blue]$file[/blue][red];[/red]
			[blue]$archived[/blue] =~ [red]s/[/red][purple]pdf[/purple][red]/[/red][purple]pdfarchived[/purple][red]/[/red][red];[/red]

			[maroon]copy[/maroon][red]([/red][red]"[/red][purple][blue]$dir[/blue]/[blue]$file[/blue][/purple][red]"[/red], [red]'[/red][purple]/usr/local/moved[/purple][red]'[/red][red])[/red] or [black][b]die[/b][/black] [red]"[/red][purple]copy failed: [blue]$![/blue][/purple][red]"[/red][red];[/red]
			[maroon]move[/maroon][red]([/red][red]"[/red][purple][blue]$dir[/blue]/[blue]$file[/blue][/purple][red]"[/red], [red]"[/red][purple][blue]$dir[/blue]/[blue]$archived[/blue][/purple][red]"[/red][red])[/red] or [black][b]die[/b][/black] [red]"[/red][purple]move failed: [blue]$![/blue][/purple][red]"[/red][red];[/red]
		[red]}[/red]
	[red]}[/red]
[red]}[/red]
[tt]------------------------------------------------------------
Pragmas (perl 5.8.8) used :
[ul]
[li]strict - Perl pragma to restrict unsafe constructs[/li]
[/ul]
Core (perl 5.8.8) Modules used :
[ul]
[li]File::Copy - Copy files or filehandles[/li]
[/ul]
[/tt]

Again, these are just style changes and do not effect the performance of the code. However, they are intended to make coding easier, less risk prone, and more readable. And in this instance they would have avoided your initial bug that was caused by mixing shell processing of a directory with perl file processing.

- Miller
 
Hi Miller,
I am curious about how exactly this statement ( and statements like this ) gets executed.
Code:
my @filenames = grep { !/^\.+$/ } readdir(DIR);

My guess is it first executes readdir() and filters out result using grep. But that is right to left execution.
Can you throw a light on this please.



--------------------------------------------------------------------------
I never set a goal because u never know whats going to happen tommorow.
 
Hi spookie,

Yes, you are right. That line is processed right to left.

It might make it easier to read for you if we simply acknowledge that grep works a lists.

Code:
[url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]@filenames[/blue] = [url=http://perldoc.perl.org/functions/grep.html][black][b]grep[/b][/black][/url] [red]{[/red] ![red]/[/red][purple]^[purple][b]\.[/b][/purple]+$[/purple][red]/[/red] [red]}[/red] [red]([/red][url=http://perldoc.perl.org/functions/readdir.html][black][b]readdir[/b][/black][/url][red]([/red]DIR[red])[/red][red])[/red][red];[/red]

Basically readdir returns all the files of the directory when called in a "list context". And then grep filters out all files that match the regex /^\.+$/. Which basically includes the '.' and '..' symlinks for the current directory and the parent directory respectively.

If that's not clear enough feel free to say so. But someone else will have to help you as I'm going out of town for a week starting in a couple hours.

- Miller
 
Thanks for the explanation Miller.


--------------------------------------------------------------------------
I never set a goal because u never know whats going to happen tommorow.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top