Having problems with file input and reading in Windows with Perl - windows

I am trying to read a file in the same directory as the Perl script as input and read from it in Windows using Perl.
Code:
$inputFile = getcwd . "/" . <STDIN>;
open (FILE, chomp($inputFile)) or die "Cannot open $inputFile: $!\n";
#lines = <FILE>;
print "#lines\n";
The error I get is:
C:/Documents and Settings/username/workspace/test.pl No such file or directory
Even though that file definitely does exist in that exact form in that exact directory. I've also tried putting the "Documents and Settings" in quotes.

The return value from chomp is not the chomped value. Factor out the chomp to before open and you should be fine.
The getcwd is needless, by the way; the concept of current directory means where to look in the absence of a full path.

Related

Perl code doesn't run in a bash script with scheduling of crontab

I want to schedule my Perl code to be run every day at a specific time. so I put the below code in bash file:
Automate.sh
#!/bin/sh
perl /tmp/Taps/perl.pl
The schedule has been specified in below path:
10 17 * * * sh /tmp/Taps/Automate.sh > /tmp/Taps/result.log
When the time arrived to 17:10 the .sh file hasn't been running. however, when I run ./Automate.sh (manually) it is running and I see the result. I don't know what is the problem.
Perl Code
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
use XML::Dumper;
use TAP3::Tap3edit;
$Data::Dumper::Indent=1;
$Data::Dumper::Useqq=1;
my $dump = new XML::Dumper;
use File::Basename;
my $perl='';
my $xml='';
my $tap3 = TAP3::Tap3edit->new();
foreach my $file(glob '/tmp/Taps/X*')
{
$files= basename($file);
$tap3->decode($files) || die $tap3->error;
}
my $filename=$files.".xml\n";
$perl = $tap3->structure;
$dump->pl2xml($perl, $filename);
print "Done \n";
error:
No such file or directory for file X94 at /tmp/Taps/perl.pl line 22.
X94.xml
foreach my $file(glob 'Taps/X*') -- when you're running from cron, your current directory is /. You'll want to provide the full path to that Taps directory. Also specify the output directory for Out.xml
Cron uses a minimal environment and a short $PATH, which may not necessarily include the expected path to perl. Try specifying this path fully. Or source your shell settings before running the script.
There are a lot of things that can go wrong here. The most obvious and certain one is that if you use a glob to find the file in directory "Taps", then remove the directory from the file name by using basename, then Perl cannot find the file. Not quite sure what you are trying to achieve there. The file names from the glob will be for example Taps/Xfoo, a relative path to the working directory. If you try to access Xfoo from the working directory, that file will not be found (or the wrong file will be found).
This should also (probably) lead to a fatal error, which should be reported in your error log. (Assuming that the decode function returns a false value upon error, which is not certain.) If no errors are reported in your error log, that is a sign the program does not run at all. Or it could be that decode does not return false on missing file, and the file is considered to be empty.
I assume that when you test the program, you cd to /tmp and run it, or your "Taps" directory is in your home directory. So you are making assumptions about where your program looks for the files. You should be certain where it looks for files, probably by using only absolute paths.
Another simple error might be that crontab does not have permission to execute the file, or no read access to "Taps".
Edit:
Other complications in your code:
You include Data::Dumper, but never actually use that module.
$xml variable is not used.
$files variable not declared (this code would never run with use strict)
Your $files variable is outside your foreach loop, which means it will only run once. Since you use glob I assumed you were reading more than one file, in which case this solution will probably not do what you want. It is also possible that you are using a glob because the file name can change, e.g. X93, X94, etc. In that case you will read the last file name returned by the glob. But this looks like a weak link in your logic.
You add a newline \n to a file name, which is strange.

looping files with bash

I'm not very good in shell scripting and would like to ask you some question about looping of files big dataset: in my example I have alot of files with the common .pdb extension in the work dir. I need to loop all of them and i) to print name (w.o pdb extension) of each looped file and make some operation after this. E.g I need to make new dir for EACH file outside of the workdir with the name of each file and copy this file to that dir. Below you can see example of my code which are not worked- it's didn't show me the name of the file and didn't create folder for each of them. Please correct it and show me where I was wrong
#!/bin/bash
# set the work dir
receptors=./Receptors
for pdb in $receptors
do
filename=$(basename "$pdb")
echo "Processing of $filename file"
cd ..
mkdir ./docking_$filename
done
Many thanks for help,
Gleb
If all your files are contained within the .Repectors folder, you can loop each of them like so:
#!/bin/bash
for pdb in ./Receptors/*.pdb ; do
filename=$(basename "$pdb")
filenamenoextention=${filename/.pdb/}
mkdir "../docking_${filenamenoextention}"
done
Btw:
filenamenoextention=${filename/.pdb/}
Does a search replace in the variable $pdb. The syntax is ${myvariable/FOO/BAR}, and replaces all "FOO" substrings in $myvariable with "BAR". In your case it replaces ".pdb" with nothing, effectively removing it.
Alternatively, and safer (in case $filename contains multiple ".pdb"-substrings) is to remove the last four characters, like so: filenamenoextention=${filename:0:-4}
The syntax here is ${myvariable:s:e} where s and e correspond to numbers for the start and end index (not inclusive). It also let's you use negative numbers, which are offsets from the end. In other words: ${filename:0:-4} says: extract the substring from $filename starting from index 0, until you reach fourth-to-the-last character.
A few problems you have had with your script:
for pdb in ./Receptors loops only "./Receptors", and not each of the files within the folder.
When you change to parent directory (cd ..), you do so for the current shell session. This means that you keep going to the parent directory each time. Instead, you can specify the parent directory in the mkdir call. E.g mkdir ../thedir
You're looping over a one-item list, I think what you wanted to get is the list of the content of ./Receptors:
...
for pdb in $receptors/*
...
to list only file with .pdb extension use $receptors/*.pdb
So instead of just giving the path in for loop, give this:
for pdb in $receptors/*.pdb
To remove the extension :
set the variable ext to the extension you want to remove and using shell expansion operator "%" remove the extension from your filename eg:
ext=.pdb
filename=${filename%${ext}}
You can create the new directory without changing your current directory:
So to create a directory outside your current directory use the following command
mkdir ../docking_$filename
And to copy the file in the new directory use cp command
After correction
Your script should look like:
receptors=./Receptors
ext=.pdb
for pdb in $receptors/*.pdb
do
filename=$(basename "$pdb")
filename=${filename%${ext}}
echo "Processing of $filename file"
mkdir ../docking_$filename
cp $pdb ../docking_$filename
done

Perl diruse not not recognized

my program takes input from the user of a file directory via command line in windows , and then runs diruse on specified path to gather information about disk space available. For some reason the error keeps saying "diruse.exe is not recognized as an internal or external command". Below is a section of my code, to view it in its entirety please go here. I took the code out of its sub to see if it would work, but it did not.
&argument_checking; #calling sub checking user arguements.
#&reading_directory; # reads user given directory.
chdir($user_directory), or die " Directory $user_directory does not exist"; #change to user directory or exit.
open(DIRUSE, "diruse.exe /* . |"); #opening user given directory path.
foreach my $directory_lines(<DIRUSE>)
{
chomp $directory_lines;
push(#directory_lines, $directory_lines); #pushing directory lines from file into an array
}
close(DIRUSE); #closing
shift(#directory_lines);
shift(#directory_lines);
pop(#directory_lines);
&chop_and_save;
&gui_creator;
That message comes from the command shell, and it means it can't find diruse.exe in the current directory or in any directory in that process's PATH.

Best way to search for a string in a file on a network drive

Here is my problem: We have a file server (Windows 2003) that people keep putting forms on that contain PII. Policy is now that the last 4 of a person's SSN is no longer allowed on any forms on our file servers. I'm trying to figure out a script to scan for a string such as "SSN" or "Last Four" in a document and all I can find are instructions/examples on how to search text files on a local machine. I have seen a lot of threads similar to this but primarily searching a txt file in a local folder. I've seen powershell scripts that do this but (don't ask why) powershell scripting is disabled on our servers.
Is this possible? I've been reading heavily into multiple Perl books to hope for a clue or get me in the right direction and have had 0 luck.
Assuming you get access to the files eventually, here's how you can go about searching a directory of files, looking for a string match.
use strict;
use warnings;
use File::Find;
our $CHECK_FILE_EXTENSION = qr/.txt$/;
File::Find::find({wanted=>\&find_ssn, no_chdir=>1},$_) for #ARGV;
exit;
sub find_ssn
{
## File::Find sets $File::Find::name with full path to file, which is the correct path to an 'open' call when 'no_chdir' is used
return unless $File::Find::name =~ $CHECK_FILE_EXTENSION;
open F,$File::Find::name || die "Can't read file, $File::Find::name, $!\n";
while(<F>)
{
if(/SSN/)
{
## file as 'SSN' in it, do your work here
}
}
close F;
}
Aside from i/o speed, there's no real difference in accessing a file remotely vs locally. It's just a file descriptor.
C:\>perl -MFile::Slurp -E "my $dir = q|//SERVER/Share/Test|; for my $file (read_dir($dir)) { say qq|$file: |, (read_file(qq|$dir/$file|) =~ /foo/) ? q|match| : q|not match| }"
bar.txt: not match
foo.txt: match

How to use perl dbmopen on Windows and Linux

I have a perl script that runs fine on Linux but fails on Windows at this point:
$freq{total} = 0;
dbmopen(%freq,$dictfile,0666) || die "Error: Cannot open dbmfile $dictfile";
$dictfile points to the proper location on the respective platforms. Changing the 0666 file permissions does not help. The file to open is a text file encoded in gb18030.
Is there a trick? Do I need to declare the encoding to open it on Window? Or possibly a different perl distro on Windows. I'm using Strawberry Perl.
Thanks.
Edit: Sorry, if I'm stating the obvious, but I just re-read the question. When you say
The file to open is a text file encoded in gb18030.
Do you mean a plain text file?
If so I think thats your problem. dbmopen is for indexed database file, ideally created by dbmopen in a previous run of you perl program. For plain text files you cannot bind them to hashes.
My previous resonse...
It works for me on Windows with Strawberry perl 5.12.1 running on Windows7x64. Which windows perl are you using? Make sure your installation has at least one of the DBM modules with it.
Some other points which might help:
You should include $! in your die statement, it will give you the error message for the failed open. So hopefully answer your question.
dbmopen will clear the contents of the %freq hash, so you will lose $freq{total} (because its 0 you may not notice). Usual pattern is: dbmopen, change some hash values, dbmclose
Edits:
$! is the variable which contains the error test of any failed "system" call. So you open line should be something like:
dbmopen(%freq,$dictfile,0666) || die "Error: Cannot open dbmfile $dictfile: $!";
To check for the standard DBM modules you can run the following from the command prompt
for %m in ( DB_File GDBM_File SDBM_File NDBM_File ODBM_File ) do #perl -M%m -e "print qq(%m: $%m::VERSION\n)"
For me that gives:
DB_File: 1.82
GDBM_File: 1.10
SDBM_File: 1.06
Can't locate NDBM_File.pm in #INC (#INC contains: C:/Nerd/StrawberryPerl/perl/site/lib C:/Nerd/StrawberryPerl/perl/vendor/lib C:/Nerd/StrawberryPerl/perl/lib .)
.
BEGIN failed--compilation aborted.
Can't locate ODBM_File.pm in #INC (#INC contains: C:/Nerd/StrawberryPerl/perl/site/lib C:/Nerd/StrawberryPerl/perl/vendor/lib C:/Nerd/StrawberryPerl/perl/lib .)
.
BEGIN failed--compilation aborted.
Which effectively meands I have DB_File, GDBM_File, and SDBM_File. But not NDBM_File or ODBM_File. Sorry I don't know how to find out which module dbmopen uses by default.
Personally I always use a specific module and then use the tie operator instead of dbmopen.

Resources