Perl Error: invalid argument while opening the file - perl

I am new in perl. I tried to execute below mentioned program:
I am trying to open a file and read the contents from the file.
$FILE=open(FILE,"\\10.82.71.28\Testing501\Test_Folder\834_KMS_FACE_834A.mms");
if($FILE)
{
print "The file: $FILE has opened successfully";
}
else
{
die "There is an error while opening the file :$!\n";
}
while($record=<FILE>)
{
print $record;
}
close(FILE);
But while executing the program, I am facing an error:
There is an error while opening the file :invalid argument

If you execute
print "\\10.82.71.28\Testing501\Test_Folder\834_KMS_FACE_834A.mms";
You get
Unrecognized escape \T passed through at a.pl line 1.
Unrecognized escape \T passed through at a.pl line 1.
Unrecognized escape \8 passed through at a.pl line 1.
\10.82.71.28Testing501Test_Folder834_KMS_FACE_834A.mms
(You do use use strict; use warnings;, right?)
You want code to produce the following string:
\\10.82.71.28\Testing501\Test_Folder\834_KMS_FACE_834A.mms
As you can see above, the following obviously does not produce the desired string:
"\\10.82.71.28\Testing501\Test_Folder\834_KMS_FACE_834A.mms"
You could use the following:
"\\\\10.82.71.28\\Testing501\\Test_Folder\\834_KMS_FACE_834A.mms"

Use a q literal to escape the back slash like this
$filepath = q{\\\10.82.71.28\Testing501\Test_Folder\834_KMS_FACE_834A.mms};
open my $FILE, '<', "$filepath" or die "path: $!"
while($record = <$FILE>) {
---
}

Try:
open my $file, '<', 'path' or die "path: $!"
while($record = <$file>) ...
Bare file handles are very old fashioned, and using the lexically scoped file handle is considered good practice. For one thing, the file will be closed when the variable goes out of scope. Also, the 3 argument form of open is really the only form that is considered respectable these days. There is really no reason to use any other form.

You've already accepted an answer, but you can always use forward slashes instead of backslashes.
$FILE=open(FILE,"//10.82.71.28/Testing501/Test_Folder/834_KMS_FACE_834A.mms");
By the way, the standard Perl way is to use the or:
open(FILE,"//10.82.71.28/Testing501/Test_Folder/834_KMS_FACE_834A.mms")
or die qq(...);
And, it is preferred to use the three-parameter form, and use a scalar variable for the file handle. It makes it easier to pass the file as a subroutine argument:
my $file_name = '//10.82.71.28/Testing501/Test_Folder/834_KMS_FACE_834A.mms';
open my $fh, "<", $file_name
or die qq(Couldn't open the file $file_name);

I got this error when git.exe used the file.
It can be really access denied in disguise.

Related

How to derefence a copy of a STDIN filehandle?

I'm trying to figure out how to get a Perl module to deference and open a reference to a filehandle. You'll understand what I mean when you see the main program:
#!/usr/bin/perl
use strict;
use warnings;
use lib '/usr/local/share/custom_pm';
use Read_FQ;
# open the STDIN filehandle and make a copy of it for (safe handling)
open(FILECOPY, "<&STDIN") or die "Couldn't duplicate STDIN: $!";
# filehandle ref
my $FH_ref = \*FILECOPY;
# pass a reference of the filehandle copy to the module's subroutine
# the value the perl module returns gets stored in $value
my $value = {Read_FQ::read_fq($FH_ref)};
# do something with $value
Basically, I want the main program to receive input via STDIN, make a copy of the STDIN filehandle (for safe handling) then pass a reference to that copy to the read_fq() subroutine in the Read_FQ.pm file (the perl module). The subroutine will then read the input from that file handle, process it, and return a value. Here the Read_FQ.pm file:
package Read_FQ;
sub read_fq{
my ($filehandle) = #_;
my contents = '';
open my $fh, '<', $filehandle or die "Too bad! Couldn't open $filehandle for read\n";
while (<$fh>) {
# do something
}
close $fh;
return $contents;
Here's where I'm running into trouble. In the terminal, when I pass a filename to the main program to open:
cat file.txt | ./script01.pl
it gives the following error message: Too bad! Couldn't open GLOB(0xfa97f0) for read
This tells me that the problem is how I'm dereferencing and opening the reference to the filehandle in the perl module. The main program is okay. I read that $refGlob = \*FILE; is a reference to a file handle and in most cases, should automatically be dereferenced by Perl. However, that isn't that case here. Does anyone know how to dereference a filehandle ref so that I can process it?
thanks. Any suggestions are greatly appreciated.
Your $filehandle should already be open - you had opened FILECOPY, taken a reference and put it in $FH_ref, which is $filehandle. If you want to re-open it again use the <& argument in open or just start reading from it right away.
If I understand correctly, you want the 3-arg equivalent of
open my $fh, '<&STDIN'
That would be
open my $fh, '<&', $filehandle

issues for a code snippet to handle the input file

I am studying a Perl program, which includes the following segment for handling an input file. I do not understand what is s/^\s+//; used for? Moreover, what are '|' and '||' stand for in open(FILE, "cat $fileName |") || die "could not open file";
open(FILE, "cat $fileName |") || die "could not open file";
while (<FILE>)
{
s/^\s+//;
my #line = split;
if ($line[0]!~ /\:/) {$mark=0}
my $var = $line[$mark];
## some other code
}
You can read the documentation for the various functions in perlfunc.
This code will open a file for reading, by the rather circumspect way of piping from cat instead of simply opening the file. The | means that the shell command cat is piped to the open command, and our file handle will read from the output.
|| is simply or. Open the pipe, and if that fails, the program dies.
while(<FILE>) will read through every line of the input and assign each line to $_. That line is then used implicitly in the substitution and split below. I.e. s/^\s+// is equal to $_ =~ s/^\s+//, and split is equal to split(' ', $_).
s/^\s+//
Will remove leading whitespace. The split will split each line on whitespace, and the elements are stored in the array #line.
Because of the use of implicit split on whitespace, the stripping the leading whitespace with s/^\s+// is not really needed, as that is done automatically.
If the first element does not contain a colon :, $mark is set to 0. Otherwise, it is not set, and will presumably use the value from the previous iteration, since it is not defined inside the loop. Finally, $var is initialized as element number $mark, which is either 0 or whatever.
ETA: As a rather insidious oops: If $mark is undefined, i.e. it does not contain a colon, then $var will still be assigned $line[0], since undef will be converted to 0, with a warning. If use warnings is not in effect, this error is silent, and therefore insidious.
This code seems to be written by someone who does not know too much about perl, and it might not be very safe to use.
The substitution trims leading whitespace that appears at the beginning of the line (^), leaving any non-whitespace characters as the first.
The || operator in open... || die ... is a high-precedence or. If open fails, die executes.
open(FILE, "cat $fileName |") is a waste of an external process. To read a file for input, simply do:
open FILE, '<', $filename or die qq{Could not open "$filename" for reading: $!};
The parentheses for the open call are optional because or does not bind tightly.
It is also better to use lexical file handles:
open my $fh, '<' $filename or die qq{Could not open "$filename" for reading: $!};
This file handle is assigned to a lexical variable that lives only within the scope it is declared. Once the program flow exits this scope, the file closes automatically.
Part of the confusion is that the developer is using the default variable, $_. Many Perl commands (I would say about 1/3 of them) act upon $_ when you don't specify the name of the variable in the function. For example, these are syntactically the same:
my $uppercase_name = uc($_);
my $uppercase_name = uc;
In both cases, the uc function will print the string in the $_ variable in upper case characters. In fact, even the print statement uses the $_ variable. Again, these are both the same:
print $_;
print;
It's frowned upon to use the default variable in newer Perl scripts because it doesn't add clarity to the program and it doesn't make the program faster. I've rewritten the same code snippet you used in order to show the missing $_ variable. It might make the code easier to understand:
open(FILE, "cat $fileName |") || die "could not open file";
while ($_ = <FILE>)
{
$_ =~ s/^\s+//;
my #line = split $_;
if ($line[0] !~ /\:/) {
$mark = 0;
}
my $var = $line[$mark];
## some other code
}
Notice that the while statement is putting the value of the line read into the $_ variable and that the substitute command (the s/^\s+//) is also operating on the $_ variable. I hope that clarifies the code a bit for you.
Now for your questions:
_[W]hat do '|' and '||' stand for?
The || means or as in do this or that. In practice, the or can be thought of as an if statement:
if (not open(FILE, "cat $fileName |")) {
die "could not open file";
}
That is, if the open statement failed, then execute the die statement. If the open statement did manage to open the file, then don't execute the die statement.
In Perl, you now see or instead of || in cases like this:
open(FILE, "cat $fileName |") or die "could not open file";
which makes the meaning a bit more obvious: Open the file, or kill the program.
The single pipe (|) at the end of the file name means execute the command in the open statement (the cat $filename) and read from the output of this command. Imagine something like this:
open (COMMAND, "java -jar foo.war|") or die "Can't execute 'java -jar foo.war'";
Now, I'm running the command java -jar foo.war and using its output in my Perl script.
You can do this the other way around too:
open (MAIL, "|mail $recipient") or die "Can't mail $recipient";
print MAIL "Dear $recipient\n\n";
print MAIL "I hope everything is well.\n";
print MAIL "Sincerely,\n\nDavid";
close MAIL;
I'm now opening the command mail $recipient and writing to it with the print statements. In this case, I'm emailing $recipient with a simple message.
I do not understand what is s/^\s+//; used for?
In the original program, it was on a line by itself:
s/^\s+//;
I've added the missing variable which should help clarify it a bit:
$_ =~ s/^\s+//;
This is the Substitute command in Perl. It's taking the $_ variable and substituting the regular expression ^\s+ with nothing. If you don't understand what are regular expressions, you should take a look at the Perldoc tutorial on the subject. Basically, this is removing all spaces, tabs, and other forms of white space from the beginning of the line.

Why does this program not find the word 'error' in my text file?

open(LOG,"logfile.txt") or die "Unable to open $logfile:$!";
print "\n";
while(<$LOG>){
print if /\berror\b/i;
}
close(LOG);
Your typo actually takes you one step closer to opening the file the right way -- namely, using the recommended 3-argument form of open.
use strict;
use warnings;
open(my $log, '<', "logfile.txt") or die "Open failed : $logfile : $!";
while (<$log>) {
...
}
This approach is better because your file handle can be stored in a lexically scoped variable (rather than in a global name like LOG). This provides an added benefit in automatically closing the file when the lexical variable goes out of scope. Also, lexical file handles can be passed around between subroutines using a more familiar syntax.
If you wanted an even more effortless open, you could do this:
#ARGV = 'logfile.txt';
while ( <> ) {
print if /\berror\b/i;
}
open LOG, "logfile.txt";
while (<LOG>) {
print if /\berror\b/i;
}
You have an error:
while (<$LOG>)
should read
while (<LOG>)
Filehandles are not variables, so no $.

How do I resolve a "print() on closed filehandle" error in Perl?

I am getting this error while executing my Perl script. Please, tell me how to rectify this error in Perl.
print() on closed filehandle MYFILE
This is the code that is giving the error:
sub return_error
{
$DATA= "Sorry this page is corrently being updated...<p>";
$DATA.= " Back ";
open(MYFILE,">/home/abc/xrt/sdf/news/top.html");
print MYFILE $DATA;
close(MYFILE);
exit;
}
I hope that now I'm clearer.
You want to do some action on MYFILE after you (or the interpreter itself because of an error) closed it.
According to your code sample, the problem could be that open doesn't really open the file, the script may have no permission to write to the file.
Change your code to the following to see if there was an error:
open(MYFILE, ">", "/home/abc/xrt/sdf/news/top.html") or die "Couldn't open: $!";
Update
ysth pointed out that -w is not really good at checking if you can write to the file, it only ‘checks that one of the relevant flags in the mode is set’. Furthermore, brian d foy told me that the conditional I've used isn't good at handling the error. So I removed the misleading code. Use the code above instead.
It appears that the open call is failing. You should always check the status when opening a filehandle.
my $file = '/home/abc/xrt/sdf/news/top.html';
open(MYFILE, ">$file") or die "Can't write to file '$file' [$!]\n";
print MYFILE $DATA;
close MYFILE;
If the open is unsuccessful, the built-in variable $! (a.k.a. $OS_ERROR) will contain the OS-depededant error message, e.g. "Permission denied"
It's also preferable (for non-archaic versions of Perl) to use the three-argument form of open and lexical filehandles:
my $file = '/home/abc/xrt/sdf/news/top.html';
open(my $fh, '>', $file) or die "Can't write to file '$file' [$!]\n";
print {$fh} $DATA;
close $fh;
An alternate solution to saying or die is to use the autodie pragma:
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
open my $fh, "<", "nsdfkjwefnbwef";
print "should never get here (unless you named files weirdly)\n";
The code above produces the following error (unless a file named nsdfkjwefnbwef exists in the current directory):
Can't open 'nsdfkjwefnbwef' for reading: 'No such file or directory' at example.pl line 7
This:
open(MYFILE,">/home/abc/xrt/sdf/news/top.html");
In modern Perl, it could be written as:
open(my $file_fh, ">", "/home/abc/xrt/sdf/news/top.html") or die($!);
This way you get a $variable restricted to the scope, there is no "funky business" if you have weird filenames (e.g. starting with ">") and error handling (you can replace die with warn or with error handling code).
Once you close $file_fh or simply go out of scope, you can not longer print to it.
I had this problem when my files were set to READ-ONLY.
Check this also, before giving up! :)
Check that the open worked
if(open(my $FH, ">", "filename") || die("error: $!"))
{
print $FH "stuff";
close($FH);
}
If you use a global symbol MYFILE as your filehandle, rather than a local lexical ($myfile), you will invariably run into issues if your program is multithreaded, e.g. if it is running via mod_perl. One process could be closing the filehandle while another process is attempting to write to it. Using $myfile will avoid this issue as each instance will have its own local copy, but you will still run into issues where one process could overwrite the data that another is writing. Use flock() to lock the file while writing to it.
Somewhere in you're script you will be doing something like:
open MYFILE, "> myfile.txt";
# do stuff with myfile
close MYFILE;
print MYFILE "Some more stuff I want to write to myfile";
The last line will throw an error because MYFILE has been closed.
Update
After seeing your code, it looks like the file you are trying to write to can't be opened in the first place. As others have already mentioned try doing something like:
open MYFILE, "> myfile.txt" or die "Can't open myfile.txt: $!\n"
Which should give you some feedback on why you can't open the file.

Why does my Perl script remove characters from the file?

I have some issue with a Perl script. It modifies the content of a file, then reopen it to write it, and in the process some characters are lost. All words starting with '%' are deleted from the file. That's pretty annoying because the % expressions are variable placeholders for dialog boxes.
Do you have any idea why? Source file is an XML with default encoding
Here is the code:
undef $/;
open F, $file or die "cannot open file $file\n";
my $content = <F>;
close F;
$content =~s{status=["'][\w ]*["']\s*}{}gi;
printf $content;
open F, ">$file" or die "cannot reopen $file\n";
printf F $content;
close F or die "cannot close file $file\n";
You're using printf there and it thinks its first argument is a format string. See the printf documentation for details. When I run into this sort of problem, I always ensure that I'm using the functions correctly. :)
You probably want just print:
print FILE $content;
In your example, you don't need to read in the entire file since your substitution does not cross lines. Instead of trying to read and write to the same filename all at once, use a temporary file:
open my($in), "<", $file or die "cannot open file $file\n";
open my($out), ">", "$file.bak" or die "cannot open file $file.bak\n";
while( <$in> )
{
s{status=["'][\w ]*["']\s*}{}gi;
print $out;
}
rename "$file.bak", $file or die "Could not rename file\n";
This also reduces to this command-line program:
% perl -pi.bak -e 's{status=["\']\\w ]*["\']\\s*}{}g' file
Er. You're using printf.
printf interprets "%" as something special.
use "print" instead.
If you have to use printf, use
printf "%s", $content;
Important Note:
PrintF stands for Print Format , just as it does in C.
fprintf is the equivelant in C for File IO.
Perl is not C.
And even IN C, putting your content as parameter 1 gets you shot for security reasons.
Or even
perl -i bak -pe 's{status=["\'][\w ]*["\']\s*}{}gi;' yourfiles
-e says "there's code following for you to run"
-i bak says "rename the old file to whatever.bak"
-p adds a read-print loop around the -e code
Perl one-liners are a powerful tool and can save you a lot of drudgery.
If you want a solution that is aware of the XML nature of the docs (i.e., only delete status attributes, and not matching text contents) you could also use XML::PYX:
$ pyx doc.xml | perl -ne'print unless /^Astatus/' | pyxw
That's because you used printf instead of print and you know printf doesn't print "%" (because it would think you forgot to type the format symbol such as %s, %f etc) unless you explicitly mention by "%%". :-)