Why can't Perl see this directory? - perl

I have this directory structure:
$ ls -F
analyze/
data.pl
input.pl
logminer.txt
logSearch.pl
readFormat.pl
Version Notes.txt
datadump.pl
format/
logminer.pl
logs/
properties.txt
unzip.exe
I run:
perl -e 'if (!(-d analyze)){ print "poo\n"}'
and it prints poo.
What is missing here? I have done tests like this earlier and it would correctly identify that the directory exists. Why not this directory?

perl -e 'if (!(-d "analyze")){ print "poo\n"}'
^-- ^---
missing quotes?
edit: changed to double quotes - forgot this was for command-line perl

First,
-d analyze
means "check if the file handle anaylyze is a directory handle". You want
-d 'analyze'
Now, you say you still get the problem by doing that, so check what error you're getting.
my $rv = -d 'analyze';
die "stat: $!" if !defined($rv);
die "Not a dir" if !$rv;
-d is just a thin wrapper around stat(2), so it's not Perl that "can't see", it's the system.
The most common errors:
The current work directory isn't what you think it is. (Many people assume it's always the directory in which the script resides.)
The file name has trailing whitespace, especially a newline. (That's not likely to be the case here.)

Related

Can't exec "/bin/sh": Argument list too long at perl

Below command in perl script is failing if there are many file in #file_to_tar, but it is working fine if we have less files in the array (#file_to_tar).
my $tar_command = "cd $ProcVars->{dropbox_dir}; tar -cvzf SmartMiles.$ProcVars->{batch_nb}.tar.gz -P #file_to_tar --remove-files";
Can some one please help me to fix the issue.
The best way is pass a very long list of files to tar is using the --from-file option:
tar -czf myarchive.tar.gz -P --from-file=$filelist --remove-files
You can also make it read the list of files from standard input by using --from-file=-
See https://www.gnu.org/software/tar/manual/html_node/files.html for more information.
You might consider, rather than calling a shell command, using the Archive::Tar Perl module instead. In particular, the "create_archive" method. This also would sidestep any potential problems arising from special characters or whitespace in the file names being interpreted by the shell your Perl code is invoking.
it is working now.
my $file_location = "$ProcVars->{dropbox_dir}/Archive_Files.csv"; open(DATA, ">$file_location") or die $!; foreach $a (#file_to_tar) { print DATA "$a\n"; } close DATA;
my $tar_command = "cd $ProcVars->{\dropbox_dir};tar -czf ABC.$ProcVars->{batch_nb}.tar.gz -P --files-from $file_location --remove-files";

How do I move a file from current directory in Perl?

Hello all who may assist. I have a problem which I seem not t understand. I am selecting files and combining them with a "cdo" command after combining, I want to move the combined files into another directory.
This worked perfectly a month ago, then I had to increase ram, which took a month to do with no work done on the script.
Here is the start of my script
use strict;
use warnings;
use File::Path;
use File::Find;
use File::Copy qw(copy);
use File::Copy qw(move);
use Path::Tiny;
use Tie::File;
use File::Cat;
Before I come to the problem, the following move command works after selecting a file
print "Copying $file\n" if $debug;
my $cmd01 = "cp $Input_Data_Dirs[$ll]/$file $Output_Base_Dirs[$mm]";
print "Doing system ($cmd01)\n" if $debug;
system ($cmd01);
So am able to move several files with the above construction, then I move into the directory. From there I combine six files into one
print "doing cat with cdo\n" if $debug;
my $cmd05 = "cdo cat #sixfiles $newfile";
print "Doing system ($cmd05)\n" if $debug;
system ($cmd05);
Here is the part which fails
#-----------------------------------------
#print "Moving combined file\n" if $debug;
#my $cmd21 = "cp $newfile $Output_Base_Dirs[$mm]/$Var_Dirs[$kk]";
#print "Doing system ($cmd21)\n" if $debug;
#system ($cmd21);
#copy $newfile, $Output_Base_Dirs[$mm]/$Var_Dirs[$kk];
move $newfile, $Output_Base_Dirs[$mm]/$Var_Dirs[$kk];
#----------------------------------------------------
The unix commands "cp" and "mv" give the error
cp: missing destination file operand after 'pr_AFR-44_CNRM-CERFACS-CNRM-CM5_historical_r1i1p1_CLMcom-CCLM4-8-17_v1_day_19710101_20001231.nc'
Try 'cp --help' for more information.
sh: 2: /home/suman/CORDEX/DATA/historical/precip: Permission denied
and
mv: missing destination file operand after 'pr_AFR-44_CNRM-CERFACS-CNRM-CM5_historical_r1i1p1_CLMcom-CCLM4-8-17_v1_day_19710101_20001231.nc'
Try 'mv --help' for more information.
sh: 2: /home/suman/CORDEX/DATA/historical/precip: Permission denied
I have made sure there is no permission problem by issuing the command
sudo chmod -Rv ugo +rwx CORDEX
On the other hand the perl in-built commands "copy" and "move" give the following errors
Argument "precip" isn't numeric in division (/) at merge_files.pl line 247.
Argument "/home/suman/CORDEX/DATA/historical" isn't numeric in division (/) at merge_files.pl line 247.
Illegal division by zero at merge_files.pl line 247.
I am really defeated by these errors.
I will appreciate any assistance if ever possible to resolve this
I have upvoted the solution from Dave Cross for the reason that it eliminates the error of non-numeric/division by zero. Thanks Dave for that.
However, after defining
my $target_dir="$Output_Base_Dirs[$mm]/$Var_Dirs[$kk]";
both the commands:
my $cmd21 = "cp -v $newfile --target-directory=$target_dir";
and
my $cmd21 = "mv -v $newfile --target-directory=$target_dir"
give the same error
cp: missing destination file operand after 'pr_AFR-44_CNRM-CERFACS-CNRM-CM5_historical_r1i1p1_CLMcom-CCLM4-8-17_v1_day_19710101_20001231.nc'
Try 'cp --help' for more information.
sh: 2: --target-directory=/home/suman/CORDEX/DATA/historical/precip: not found
yet the target_dir exists.
The two perl commands
copy $newfile, "$target_dir" or die "copy operation failed: $!";
move $newfile, "$target_dir" or die "move operation failed: $!";
move operation failed: No such file or directory at merge_files.pl line 249.
copy operation failed: No such file or directory at merge_files.pl line 248.
I am really baffled.
move $newfile, $Output_Base_Dirs[$mm]/$Var_Dirs[$kk];
This is wrong. When combining two variables like this, you need to put them in a string.
move $newfile, "$Output_Base_Dirs[$mm]/$Var_Dirs[$kk]";
Without that, Perl thinks you're trying to do a division sum.

what is the meaning of -s in Perl and how does it work?

I have a perl program like
$var= "hello world";
$var = -s $var;
print $var;
When we print the value of $var, it shows a error like
Use of uninitialized value $var in print at line 3.
Can anyone explain how this works. What is the -s does? Is it a function? I couldn't find snyhing about it in perldoc.
The -s file test operator accepts either a file name string or a valid opened file handle, and returns the size of the file in bytes. If the file doesn't exist (I presume you have no file called hello world) then it returns undef
It is documented in perldoc -f -X
There is also a perl command-line switch -s which is unrelated. It is documented in perldoc perlrun. That is the documentation that you have found, but it is irrelevant to using -s within a Perl program
-s is one of many file tests available in Perl. This particular test returns file size in bytes, so it can be used to check if file is empty or not.
In your sample code the test returned undef, as it could not find file named hello world.
You can read more about file tests in Perl here: http://perldoc.perl.org/functions/-X.html
-s is an oddly named function documented in -X. But despite the dash in its name, -s is just like any other function.
-s returns the size of the file provided as an argument. On error, it returns undef and sets $!.
To find out what error you are getting, check if the size is undefined.
defined( my $size = -s $qfn )
or die("Can't stat \"$qfn\": $!\n");
In this case, it's surely because hello world isn't a path to a file.

Perl command failing if I use -e option to check whether the file exists or not

I have perl version v5.8.3 installed on my windows machine.
While running a perl script having the below code, failing.
if(-e $file1)
I knew that this checks whether file1 is present or not.
The error just shown "perl command failed". Nothing else.
Could you please help me on this
You're using a version of Perl from 2004. You should seriously consider upgrading.
The file test operators like -e have been part of Perl for a very long time. They are certainly supported by Perl 5.8.3.
You say that your error is "perl command failed". That is not an error that is generated by Perl, so I suspect there is something else going on here that you're not telling us about (presumably because you think it isn't important).
If I had to guess why your -e test is failing, I'd say that it's because $file1 doesn't contain any information about the directory where the file can be found, and therefore Perl is looking in the wrong place. Perhaps you can get more information with code like this:
use Cwd;
if (-e $file1) {
...
} else {
die "Can't find file: " . cwd() . '/' . $file1;
}
This will show you where Perl is looking for the file.

How do I run a Perl script on multiple input files with the same extension?

How do I run a Perl script on multiple input files with the same extension?
perl scriptname.pl file.aspx
I'm looking to have it run for all aspx files in the current directory
Thanks!
In your Perl file,
my #files = <*.aspx>;
for $file (#files) {
# do something.
}
The <*.aspx> is called a glob.
you can pass those files to perl with wildcard
in your script
foreach (#ARGV){
print "file: $_\n";
# open your file here...
#..do something
# close your file
}
on command line
$ perl myscript.pl *.aspx
You can use glob explicitly, to use shell parameters without depending to much on the shell behaviour.
for my $file ( map {glob($_)} #ARGV ) {
print $file, "\n";
};
You may need to control the possibility of a filename duplicate with more than one parameter expanded.
For a simple one-liner with -n or -p, you want
perl -i~ -pe 's/foo/bar/' *.aspx
The -i~ says to modify each target file in place, and leave the original as a backup with an ~ suffix added to the file name. (Omit the suffix to not leave a backup. But if you are still learning or experimenting, that's a bad idea; removing the backups when you're done is a much smaller hassle than restoring the originals from a backup if you mess something up.)
If your Perl code is too complex for a one-liner (or just useful enough to be reusable) obviously replace -e '# your code here' with scriptname.pl ... though then maybe refactor scriptname.pl so that it accepts a list of file name arguments, and simply use scriptname.pl *.aspx to run it on all *.aspx files in the current directory.
If you need to recurse a directory structure and find all files with a particular naming pattern, the find utility is useful.
find . -name '*.aspx' -exec perl -pi~ -e 's/foo/bar/' {} +
If your find does not support -exec ... + try with -exec ... \; though it will be slower and launch more processes (one per file you find instead of as few as possible to process all the files).
To only scan some directories, replace . (which names the current directory) with a space-separated list of the directories to examine, or even use find to find the directories themselves (and then perhaps explore -execdir for doing something in each directory that find selects with your complex, intricate, business-critical, maybe secret list of find option predicates).
Maybe also explore find2perl to do this directory recursion natively in Perl.
If you are on Linux machine, you could try something like this.
for i in `ls /tmp/*.aspx`; do perl scriptname.pl $i; done
For example to handle perl scriptname.pl *.aspx *.asp
In linux: The shell expands wildcards, so the perl can simply be
for (#ARGV) {
operation($_); # do something with each file
}
Windows doesn't expand wildcards so expand the wildcards in each argument in perl as follows. The for loop then processes each file in the same way as above
for (map {glob} #ARGV) {
operation($_); # do something with each file
}
For example, this will print the expanded list under Windows
print "$_\n" for(map {glob} #ARGV);
You can also pass the path where you have your aspx files and read them one by one.
#!/usr/bin/perl -w
use strict;
my $path = shift;
my #files = split/\n/, `ls *.aspx`;
foreach my $file (#files) {
do something...
}