How to Write a Variable to File in Perl - perl

I have info contained in a variable that I need to have written to a file. My script needs to be create the file and then write to it.
Here's my current script:
my $file_location = '/network/$custom_directory/$custom_filename';
open(my $file ">", $file_location) or die $!;
print $file "$variable_data";
close $file;
I'm getting the feeling that my script is getting hung up on the actual file creation, rather than the variable-writing process.
The error I get when I run the script is: 'No such file or directory' at the line where I try to open the file.

You have a syntax error in your programme. All three arguments of open must be separated by commas.
open my $file, '>', $file_location or die $!;
Single quotes do not interpolate, unlike double quotes, so you probably need them in the file path:
my $file_location = "/network/$custom_directory/$custom_filename";
BTW: Including a sole variable into double quotes server no purpose for string contents. You can equivalently
print $file $variable_data;

You didn’t say what your error is.
But you’re missing a comma.
You also have the wrong quotes.
You also (probably) forgot the newline at the end.
And you forgot to check that the close succeeded lest your filesystem should have filled up.
You may have forgotten the binmode or the encoding.
Which gives you something like this, with obligatory preamble:
#!/usr/bin/perl
use strict;
use warnings;
my $custom_directory = "something old";
my $custom_filename = "something new";
my $data = "something borrowed";
my $path = "/network/$custom_directory/$custom_filename";
open(my $handle, ">", $path) || die "can't open $path: $!";
binmode($handle); # for raw; else set the encoding
print $handle "$data\n";
close($handle) || die "can't close $path: $!";

Two things: First the file location is in single-quotes, so the $ variables won't be interpolated. Second, you're missing a comma in the call to open. The code should read:
my $file_location = "/network/$custom_directory/$custom_filename";
open(my $file, ">", $file_location) or die $!;

First,
use strict;
use warnings;
may help. Second, variable interpolation requires double quoted strings:
my $file_location = "/network/$custom_directory/$custom_filename";
Third, you may probably need a \n at the print statement:
print $file "$variable_data\n";
And finally, your open statement should be:
open my $file, ">", $file_location or die $!;

Related

Counting number of lines with conditions

This is my script count.pl, I am trying to count the number of lines in a file.
The script's code :
chdir $filepath;
if (-e "$filepath"){
$total = `wc -l < file.list`;
printf "there are $total number of lines in file.list";
}
i can get a correct output, but i do not want to count blank lines and anything in the file that start with #. any idea ?
As this is a Perl program already open the file and read it, filtering out lines that don't count with
open my $fh, '<', $filename or die "Can't open $filename: $!";
my $num_lines = grep { not /^$|^\s*#/ } <$fh>;
where $filename is "file.list." If by "blank lines" you mean also lines with spaces only then chagne regex to /^\s*$|^\s*#/. See grep, and perlretut for regex used in its condition.
That filehandle $fh gets closed when the control exits the current scope, or add close $fh; after the file isn't needed for processing any more. Or, wrap it in a block with do
my $num_lines = do {
open my $fh, '<', $filename or die "Can't open $filename: $!";
grep { not /^$|^\s*#/ } <$fh>;
};
This makes sense doing if the sole purpose of opening that file is counting lines.
Another thing though: an operation like chdir should always be checked, and then there is no need for the race-sensitive if (-e $filepath) either. Altogether
# Perhaps save the old cwd first so to be able to return to it later
#my $old_cwd = Cwd::cwd;
chdir $filepath or die "Can't chdir to $filepath: $!";
open my $fh, '<', $filename or die "Can't open $filename: $!";
my $num_lines = grep { not /^$|^\s*#/ } <$fh>;
A couple of other notes:
There is no reason for printf. For all normal prints use say, for which you need use feature qw(say); at the beginning of the program. See feature pragma
Just in case, allow me to add: every program must have at the beginning
use warnings;
use strict;
Perhaps the original intent of the code in the question is to allow a program to try a non-existing location, and not die? In any case, one way to keep the -e test, as asked for
#my $old_cwd = Cwd::cwd;
chdir $filepath or warn "Can't chdir to $filepath: $!";
my $num_lines;
if (-e $filepath) {
open my $fh, '<', $filename or die "Can't open $filename: $!";
$num_lines = grep { not /^$|^\s*#/ } <$fh>;
}
where I still added a warning if chdir fails. Remove that if you really don't want it. I also added a declaration of the variable that is assigned the number of lines, with my $total_lines;. If it is declared earlier in your real code then of course remove that line here.
perl -ne '$n++ unless /^$|^#/ or eof; print "$n\n" if eof'
Works with multiple files too.
perl -ne '$n++ unless /^$|^#/ or eof; END {print "$n\n"}'
Better for a single file.
open(my $fh, '<', $filename);
my $n = 0;
for(<$fh>) { $n++ unless /^$|^#/}
print $n;
Using sed to filter out the "unwanted" lines in a single file:
sed '/^\s*#/d;/^\s*$/d' infile | wc -l
Obviously, you can also replace infile with a list of files.
The solution is very simple, no any magic.
use strict;
use warnings;
use feature 'say';
my $count = 0;
while( <> ) {
$count++ unless /^\s*$|^\s*#/;
}
say "Total $count lines";
Reference:
<>

Perl can't find file

I am a relatively infrequent user of Perl. I have written a script that takes two input files with the same name but different extensions, processes them and outputs a third file. It works when I specify the name of the file, but I want it to search for all relevant files in a directory and process all of them. However, when I do this it keeps saying there is no such file or directory - even though I'm sure there is. I've looked at all the relevant pages on this site and tried the suggestions there, but it still doesn't work. I'm stumped.
Here is the code, missing the processing of the files themselves, as that is long and not relevant.
use strict;
use warnings;
use autodie;
#specify single file - works when this is not commented and the loops below are
#my $file = "BE_Read01_f2-2";
#on a Mac
my $dir = "/Users/sashacalhoun/Documents/supervision/tariq/Syllables";
opendir(my $dh, $dir);
while (my $file = readdir($dh)) {
if($file=~s/(.+-CV)\.TextGrid/$1/) {
print "$file\n";
open(my $syl, "<", "$dir/${file}.par");
while(my $line=<$syl>) {
#processes this file - not included
}
close($syl);
my $gridfile = "$file-CV.TextGrid";
my $outfile = "$file-syl.TextGrid";
open(my $grid, "<", $gridfile);
open(my $out, ">", $outfile);
while(my $line=<$grid>) {
print $out $line;
# other processing of this file
}
close($grid);
close($out);
}
}
It says: Can't open '/Users/sashacalhoun/Documents/supervision/tariq/Syllables/BE_Read01_f2-1-CV.par' for reading: 'No such file or directory' at ./get_syl.pl line 36
Thanks very much for your help.
From your error message, it is apparent that the line causing the error is this line:
open(my $syl, "<", "$dir/${file}.par");
it keeps saying there is no such file or directory - even though I'm sure there is.
You can prove to yourself that no such file exists by copying the path in the error message:
Can't open
'/Users/sashacalhoun/Documents/supervision/tariq/Syllables/BE_Read01_f2-1-CV.par'
for reading: 'No such file or directory' at ./get_syl.pl line 36
and doing this:
$ ls /Users/sashacalhoun/Documents/supervision/tariq/Syllables/BE_Read01_f2-1-CV.par
And, instead of constructing paths yourself, you should consider using File::Spec, etc.:
use File::Spec::Functions;
my $path = catfile $dirname, $fname;
And, you should probably check whether the filename is a file or directory before constructing your path:
if (-f $path -r $path) { #then it's a file that is readable...
#Here you might want to skip files whose names start with a '.', i.e. hidden files
}
And, your debugging print statement should be this:
my $path = "$dir/$file.par";
print "$path\n";
open(my $syl, "<", "$path.par");
By the way, if you don't like typing \n after every print statement, you can use say():
say "After printing this text, perl automatically adds a '\n' to the end of the output";
You do have to employ a use statement for say() to work, e.g.
use 5.010;
And, you should add a die() clause to your opendir()/open() statements:
opendir(my $DIR, $dir)
or die "Couldn't open $dir: $!";

renaming file with user input name

I want to rename my temporary file "file3.c" to user input file name.
Using rename or move command from File::copy doesn't rename it.
use strict;
use warnings;
use File::Copy;
#input header file
print "Input file1:\n";
$input = <>;
open(FILE1, $input) || die "couldn't open the file!";
open(FILE3, '>>file3.c') || die "couldn't open the file!";
...
#some work on file3.c
...
close(FILE1);
close(FILE3);
#renaming prepended temporary file name to original file name
rename("file3.c", "$input");
OUTPUT
no renaming occurs
How do I rename it?
You probably only need to chomp your input to remove the newline:
chomp(my $input = <>);
And you should always check for an error $! when performing file operations:
rename($foo, $bar) or die "Cannot rename: $!";
Also, you should most often use or instead of ||, since || has higher precedence. For example, this is a common beginner mistake, that is rather hard to discover:
open my $fh, "<", $file || die $!; # WRONG!
Because logical or || has higher precedence than comma ,, the die statement will never happen, unless $file happens to be a false value.

Perl opening dynamically generated files

I am using CGI script for my website. And I have problem with opening a dynamically generated file. Here is the code:
#!/usr/bin/perl
my #output = `/export/es_share/Zhou/./notification_finder.sh range $date $time $range $ulh TestProd1 $actionname`;
my $filen = $output[0];
open(my $result, "<", $filen) or die "Can't open $filen - $!";
Do something with the file...
Always fails, with the output:
Can't open /var/tmp/notification-finder-1375086676-658183725.tmp -
No such file or directory at /var/www/cgi-bin/appsupport/logapp_test/perltest.cgi line X.
While as this succeeds:
#!/usr/bin/perl
open(my $result, "<", /var/tmp/notification-finder-1375086676-658183725.tmp) or die "Can't open $filen - $!";
Do something with the file...
I have also checked if it was the problem of asynchronous execution of the backticks problem, but from my research on stackoverflow it does not seem to be the issue. I also tried this:
#!/usr/bin/perl
my #output = `/export/es_share/Zhou/./notification_finder.sh range $date $time $range $ulh TestProd1 $actionname`;
sleep(10);
my $filen = $output[0];
open(my $result, "<", $filen) or die "Can't open $filen - $!";
Do something with the file...
I have found this similar issue here, but I don't seem to have the same problem as the asker... Thanks for reading this far.
The error indicates there is a newline on the end of $filen, otherwise it would be:
Can't open /var/tmp/notification-finder-1375086676-658183725.tmp - No such file or directory at /var/www/cgi-bin/appsupport/logapp_test/perltest.cgi line XXXXXXXXX.
Remove it with:
chomp $filen;

Perl reading and writing in files

Alright, so I'm back with another question. I know in Python there is a way to read in a file without specifying which file it will be, until you are in the command prompt. So basically you can set the script up so that you can read in any file you want and don't have to go back and change the coding every time. Is there a way to do this in Perl? If so, can you write files like that too? Thanks.
This is what I have:
open (LOGFILE, "UNSUCCESSFULOUTPUT.txt") or die "Can't find file";
open FILE, ">", "output.txt" or die $!;
while(<LOGFILE>){
print FILE "ERROR in line $.\n" if (/Error/);
}
close FILE;
close LOGFILE;
This is what I have nome:
#!/usr/local/bin/perl
my $argument1 = $ARGV[0];
open (LOGFILE, "<$argument1") or die "Can't find file";
open FILE, ">>output.txt" or die $!;
while(<LOGFILE>){
print FILE "ERROR in line $.\n" if (/Error/);
}
close FILE;
close LOGFILE;
And it's still not appending...
Command line arguments are provided in #ARGV. You can do as you please with them, including passing them as file names to open.
my ($in_qfn, $out_qfn) = #ARGV;
open(my $in_fh, '<', $in_qfn ) or die $!;
open(my $out_fh, '>', $out_qfn) or die $!;
print $out_fh $_ while <$in_fh>;
But that's not a very unixy way of doing things. In unix tradition, the following will read from every file specified on the command line, one line at a time:
while (<>) {
...
}
Output is usually placed in files through redirection.
#!/usr/bin/env perl
# This is mycat.pl
print while <>;
# Example usage.
mycat.pl foo bar > baz
# Edit foo in-place.
perl -i mycat.pl foo
The only time one usually touches #ARGV is to process options, and even then, one usually uses Getopt::Long instead of touching #ARGV directly.
Regarding your code, your script should be:
#!/usr/bin/env perl
while (<>) {
print "ERROR in line $.\n" if /Error/;
}
Usage:
perl script.pl UNSUCCESSFULOUTPUT.txt >output.txt
You can get rid of perl from the command if you make script.pl executable (chmod u+x script.pl).
This is what I believe you want:
#!usr/bin/perl
my $argument1 = $ARGV[0];
open (LOGFILE, "<$argument1") or die "Can't find file";
open (FILE, ">output.txt") or die $!;
while(<LOGFILE>){
print FILE "ERROR in line $.\n" if (/Error/);
}
close FILE;
close LOGFILE;
Ran as from the command line:
> perl nameofpl.pl mytxt.txt
For appending change this line:
open (FILE, ">output.txt") or die $!;
To the remarkably similar:
open (FILE, ">>output.txt") or die $!;
I assume you are asking how to pass an argument to a perl script. This is done with the #ARGV variable.
use strict;
use warnings;
my $file = shift; # implicitly shifts from #ARGV
print "The file is: $file\n";
You can also make use of the magic of the diamond operator <>, which will open the arguments to the script as files, or use STDIN if no arguments are supplied. The diamond operator is used as a normal file handle, typically while (<>) ...
ETA:
With the code you supplied, you can make it more flexible by doing this:
use strict;
use warnings; # always use these
my $file = shift; # first argument, required
my $outfile = shift // "output.txt"; # second argument, optional
open my $log, "<", $file or die $!;
open my $out, ">", $outfile or die $!;
while (<$log>) {
print $out "ERROR in line $.\n" if (/Error/);
}
Also see ikegami's answer on how to make it more like other unix tools, e.g. accept STDIN or file arguments, and print to STDOUT.
As I commented in your earlier question, you may simply wish to use an already existing tool for the job:
grep -n Error input.txt > output.txt