Rewrite last part of file read - fwrite

I see how to change the pointer in a file to read just part of the file (fseek).
Does setting the pointer for rewriting ('fwrite') part of the file work the same way?
After the 'fread' do I leave pointer alone or backup from current position to rewrite what I just read?
Note the idea is to exchange two blocks of the file for randomization.

Yes fwrite works like fread. After fread, you need to fseek to the position to write to. Here's an example:
// get temporary directory
$tmp_dir = sys_get_temp_dir() . DIRECTORY_SEPARATOR;
// get temporary file name in temporary dir
$tmp_filename = tempnam($tmp_dir, '');
// open temp file for read and write
$handle = fopen($tmp_filename, 'r+');
$str = 'the quick brown fox jumps over the lazy dog';
echo($str . PHP_EOL);
// write string to file
$result = fwrite($handle, $str);
$pos = strpos($str, 'jumps');
// seek to jumps position
$result = fseek($handle, $pos);
// change jumps for sneaks under
$str2 = 'sneaks under';
$result = fwrite($handle, $str2);
// get file size
$file_size = filesize($tmp_filename);
// seek to file start
$result = fseek($handle, 0);
// read from file
$result = fread($handle, $file_size);
echo($result);
// close file
fclose($handle);
$ php src/fwrite.php
the quick brown fox jumps over the lazy dog
the quick brown fox sneaks under the lazy dog

Related

Perl Script did not find the newest file

I use the following perl script from "https://exchange.nagios.org/directory/Plugins/Operating-Systems/Linux/Check-Newest-files-age-and-size-in-Diredtory/"
But in these script is an Error. The script is not showing the newest file. Can someone find the mistake? In the comments of the site have wrote somebody, that in line 22 the mistake is. I can't find it:
Here is the code:
# Check that file exists (can be directory or link)
unless (-d $opt_f) {
print "FILE_AGE CRITICAL: Folder not found - $opt_f\n";
exit $ERRORS{'CRITICAL'};
}
my $list = opendir DIRHANDLE, $opt_f or die "Cant open directory: $!";
while ($_ = readdir(DIRHANDLE))
{
$file=sprintf("%s/%s",$opt_f,$_);
$attrs = stat("$file");
$diff = time()-$attrs->mtime;
if($temp == 0)
{
#$temp=$diff;
$new=$file;
}
if($_ ne "." && $_ ne "..")
{
if($diff<$temp)
{
$temp=$diff;
$new=$_;
}
else
{
$temp=$diff; $new=$_;
}
}
}
$st = File::stat::stat($opt_f."/".$new);
$age = time - $st->mtime;
$size = $st->size;
Example:
I have some files on a filer (backups in a .img File). I use this script, to check the newest file size. If I create a new folder with a new file, the check looks to the correct file. But if I create a second file, the check looks to the old file anytime. If I create a third file, the check goes to the correct file. The fourth file is wrong and the fifth file is correct again(and so on)
An easy (easier?) way to do this would be to use the built-in glob function to read the directory instead of opening it, and then use simple file tests to sort the files by creation or modification time:
my #files = sort {-M($a) <=> -M($b)} glob "*"; # or -C for creation
# $files[0] is the newest file
A list of file test operators is at
https://users.cs.cf.ac.uk/Dave.Marshall/PERL/node69.html
Note that -C and -M relate to when the script started, so for long-running or daemon scripts you might need to do something a bit different.
You want to find the earliest mtime, so we're talking about a simple comparison of the previously-found earlier mtime with the mtime of the current file. But there's so much code beyond that in what you posted ...and the first thing you do with the value you want to compare is change it? What?
Let's start over.
my $earliest_mtime = -1;
my $earliest_qfn;
while (defined( my $fn = readdir($dh) )) {
next if $fn =~ /^\.\.?\z/;
my $qfn = "$dir_qfn/$fn";
my $stats = stat($qfn)
or warn("Can't stat \"$qfn\": $!\n"), next;
my $mtime = $stats->mtime;
if ($mtime < $earliest_mtime) {
$earliest_mtime = $mtime;
$earliest_qfn = $qfn;
}
}
if (defined($earliest_qfn)) {
say $earliest_qfn;
}
The biggest issue with the script seems to be that line 12 calls the core version of stat but line 13 expects the output to be that of File::stat::stat(). I suspect that testing for '.' or '..' should be done at the top of the while loop and all the variables should be defined before they are used.
As Jeremy has said, you're better off sorting an array of the files and pushing/poping the first/last value, depending on what you're looking for.

Opening a file inside a subroutine for read/write in Perl

I am trying to open a file inside a subroutine to basically substitute some lines in the file. But since, it was not working, I tried a simpler way of printing a line instead of substitute, for debug purposes. Following is the subroutine code.
sub replace {
while (<INPUT_FILE>){
my $cell = $_[0];
our $rpl;
if ($_=~ /^TASK\|VALUE = (.*)/ ) {
my $task = $1;
chomp $task;
$rpl = $cell . '_' . $task . '_bunch_rpl';
print "000: $rpl\n";
}
elsif ($_=~ /^(.*)\|VALUE = (.*)/ ) {
my $line = $_;
chomp $line;
my $ip_var = $1;
my $ip_val = $2;
chomp $ip_var;
chomp $ip_val;
my $look= $ip_var."|VALUE";
open(REPLAY_FILE, "+<$rpl") || die "\ncannot open $rpl\n";
while (my $rpl_sub = <REPLAY_FILE>) {
if ($rpl_sub =~ /^$line/) {
print "\n 111: $ip_val";
}
}
close REPLAY_FILE;
}
elsif ($_=~ /^\s*$/) {
print "\n";
return ;
}
}
}
The code prints the following as of now.
000: lfr_task62_bunch_rpl
111: 2.0.9.0
111: INLINE
111: POWER
000: aaa_task14_bunch_rpl
Expected output is:
000: lfr_task62_bunch_rpl
111: 2.0.9.0
111: INLINE
111: POWER
000: aaa_task14_bunch_rpl
111: 0.45
111: NO
The input sample is:
TASK_CELL_NAME|VALUE = lfr
TASK|VALUE = task62
TASK_VERSION|VALUE = 2.0.9.0
CHIP_PKG_TYPE|VALUE = INLINE
JUNK_LINE = JUNK
JUNK_LINE = JUNK
FULL_ESD|VALUE = POWER
TASK_CELL_NAME|VALUE = aaa
TASK|VALUE = task14
CUSTOM_CELL_DENSITY|VALUE = 0.45
CUSTOM_CELL_SS|VALUE = NO
Can someone tell me the mistake I am doing here?
UPDATE: Main code below
my #cell_names;
open(INPUT_FILE, "<$ip_file") || die "\n!!!ERROR OPENING INPUT FILE. EXITING SCRIPT!!!\n";
while (<INPUT_FILE>) {
if ($_=~ /(.*) =\n/ ) {
$mw -> messageBox(-message=> "\nFormat not correct on line $. of input file. Exiting script\n");
exit;
}
elsif ($_=~ /(.*) =\s+\n/ ) {
$mw -> messageBox(-message=> "\nFormat not correct on line $. of input file. Exiting script\n");
exit;
}
elsif ($_=~ /(.*) = \s+(.*)/ ) {
$mw -> messageBox(-message=> "\nFormat not correct on line $. of input file. Exiting script\n");
exit;
}
elsif ($_=~ /^TASK_CELL_NAME\|VALUE = (.*)/ ) {
my $cell_name = $1;
chomp $cell_name;
unless(grep( /^$cell_name $/, #cell_names )) {
push #cell_names, "$cell_name ";
#$count++;
#print "\nCELL NAME: $cell_name\n";
replace($cell_name);
}
}
}
close INPUT_FILE;
Update: lfr_task62_bunch_rpl before running code:
# Select fund
FUND|VALUE = mmi
# Select bank
BANK|VALUE = citi
# Select cell name
TASK_CELL_NAME|VALUE = lfr
# Select task
TASK|VALUE = task62
# Select task version
TASK_VERSION|VALUE = 1.0.9.0
# Select fund type
FULL_ESD|VALUE = MUTUAL
# Select customer premium
CUSTOM_CELL_SS|VALUE = YES
# Select customer brand density
CUSTOM_CELL_DENSITY|VALUE = 0.76
# Select card chip
CHIP_PKG_TYPE|VALUE|VALUE = OUTLINE
Expected lfr_task62_bunch_rpl after running code:
# Select fund
FUND|VALUE = mmi
# Select bank
BANK|VALUE = citi
# Select cell name
TASK_CELL_NAME|VALUE = lfr
# Select task
TASK|VALUE = task62
# Select task version
TASK_VERSION|VALUE = 2.0.9.0
# Select fund type
FULL_ESD|VALUE = POWER
# Select customer premium
CUSTOM_CELL_SS|VALUE = YES
# Select customer brand density
CUSTOM_CELL_DENSITY|VALUE = 0.76
# Select card chip
CHIP_PKG_TYPE|VALUE|VALUE = INLINE
It's not really clear what this code is supposed to do. But I can immediately see a few problems with the logic. Let's step through a few iterations of the loop, using your sample data file.
The first time, the line of data read in is:
TASK_CELL_NAME|VALUE = lf
So that matches on your second regex match. You set a few variables and then (because $ip_var is equal to "TASK_CELL_NAME") you skip to the else clause and close a filehandle that isn't open.
Next time round, we read:
TASK|VALUE = task62
That matches your first regex match. The variable $rpl_file is set to "XXX_lfr_bunch_rpl" (where 'XXX' is the parameter passed to the subroutine - obviously, I don't know what that is). You print a "000" line with that value and open the file with that name in r/w mode.
Third time round, we get this data:
TASK_VERSION|VALUE = 2.0.9.0
This matches your second regex and because $ip_var isn't equal to "TASK_CELL_NAME" we go into the if clause. This reads from your open filehandle and prints a "111" line. But this generates a warning if you have use warnings switched on as the line includes the value of $rpl_file which is currently defined. It was set the last time around the loop, but because the variable is declared inside the loop, it has now lost its value. We then close the filehandle.
The fourth iteration will be the last one that's really interesting. We get this data:
CHIP_PKG_TYPE|VALUE = INLINE
This also matches the second regex, so we do a lot the same as the third iteration. But the difference here is that when we try to read from the filehandle, we get a warning because that filehandle is closed. Oh, and then we close it again for good measure :-)
As I said at the start, I can't really work out what we're trying to do here. But I can see that the logic is very strange. You really need to go back to the drawing board and think through your logic again.
Update:
With the updated version of your code, I'm still seeing problems.
On the first iteration, the data is:
TASK_CELL_NAME|VALUE = lf
So this matches your second regex. That goes into the piece of code that opens the other file and tries to read from it. But it expects to find the filename in $rpl and that variable hasn't been given a value yet. So the open() fails and the program dies.

Reading from two files (one raw, one XMP) with ExifTool

I am new to PERL and even newer to ExifTool—and am therefore likely missing something quite basic.
The goal is to read XMP fields from a photo file. Looking at the exiftool documentation on both the ExifTool site and CPAN, I was able to read tagged jpeg and the XMP sidecar files, both without issues.
The problem is when I read from a raw file—which obviously doesn't have custom fields—I would get an error with an uninitialized value. That is to be expected.
So, I want to have code that says "if you read a field/tag from the raw file and it isn't there, look at the associated XMP file, and if that fails, return a blank string."
I therefore tried to open a second instance of ExifTool, such as:
my $exifInfo = ImageInfo($filePath);
goes to
my $exifInfoXMP = ImageInfo($filePathXMP);
But that keeps failing. If I read the XMP directly from the get-go, it works just fine, so I am getting the impression that I cannot read two ExifTool structures at the same time (which can't be right; I have to be the error here). The code below works, but I cannot "interleave" the conditionals on the two files. I have to process the raw first, then run a second pass with a new handler for the XMP. Knowing how efficient PERL is, my approach cannot possibly be a good one (even though it does the job).
In particular, there is one line that puzzles me. If I remove it, nothing works. (it should be well marked).
$filePath =~ s/$photoExtensions$/.XMP/i;
That line essential does the same as reading the XMP from the get-go (not my ideal solution).
Anyone have an idea as to where I am messing up?
Thanks,
Paul
header [EDITED TO SHOW ALL OPTIONS; HAD SHOWN ALL USED IN QUESTION]
#!/usr/bin/perl
# load standard packages
use strict;
use warnings;
use Data::Dumper;
use File::Find;
no warnings 'File::Find';
use Image::ExifTool ':Public';
# define proxy for ExifTool
my $exifTool = new Image::ExifTool;
my $exifToolXMP = new Image::ExifTool;
# turn on immediate updates
$|=1;
# common extensions that I want to recognize
my $photoExtensions = "\.(jpg|crw|cr2|cr3|rw2|orf|raw|nef|arw|dng)";
my $imageExtensions = "\.(tiff|tif|psd|png|eps|hdr|exr|svg|gif|afphoto|pdf)";
my $videoExtensions = "\.(flv|vob|ogv|avi|mts|m2ts|mov|qt|wmv|mp4|m4p|m4v|svi|3gp|3g2)";
my $audioExtensions = "\.(aiff|aac|wav|mp3|m4a|m4p|ogg|wma)";
my $appFileExtensions = "\.(on1|cos|cof)";
my $GPSFileExtensions = "\.(gpx|kml|kmz|log)";
# start main program
main();
routine in question
sub listKeywords {
print "Reads and displays file information from certain tags (typically set in Photomechanic):\n";
print "\t1. Subject\n";
print "\t2. Hierarchical Subject\n";
print "\t3. Supplemental Categories\n";
print "\t4. Label Name 1\n";
print "\t5. Label Name 2\n";
print "\t6. Label Name 3\n";
print "\t7. Label Name 4\n\n";
print "List Keywords ---\n\tEnter file name (with path) --> ";
my $filePath = <STDIN>;
chomp $filePath;
$filePath =~ s/\\//g;
$filePath =~ s/\s+$//;
########################################################
# COMMENT OUT THE FOLLOWING LINE AND NOTHING WORKS;
# $filePathXMP should be defined anyway, which suggests to
# me that the second invocation of ImageInfo doesn't actually occur.
# But I don't understand why.
$filePath =~ s/$photoExtensions$/.XMP/i;
print "\n\n";
my $filePathXMP = $filePath;
$filePathXMP =~ s/$photoExtensions$/.XMP/i; # TO FIX: filename may not have uppercase extension
# Get Exif information from image file
my $exifInfo = $exifTool->ImageInfo($filePath);
# my $exifInfoXMP = $exifToolXMP->ImageInfo($filePath =~ s/$photoExtensions$/.XMP/gi);
print "XMP Sidecar: \[$filePathXMP\]\n\n";
########################################################
# Get Specific Tag Value
my $hierarchicalSubject = $exifTool->GetValue('HierarchicalSubject');
my $subject = $exifTool->GetValue('Subject');
my $supplementalCategories = $exifTool->GetValue('SupplementalCategories');
my $labelName1 = $exifTool->GetValue('LabelName1');
my $labelName2 = $exifTool->GetValue('LabelName2');
my $labelName3 = $exifTool->GetValue('LabelName3');
my $labelName4 = $exifTool->GetValue('LabelName4');
my $exifInfo = ImageInfo($filePathXMP);
if (not defined $hierarchicalSubject) {$hierarchicalSubject = $exifTool->GetValue('HierarchicalSubject');}
if (not defined $hierarchicalSubject) {$hierarchicalSubject = "";}
if (not defined $subject) {$subject = $exifTool->GetValue('Subject');}
if (not defined $subject) {$subject = "";}
if (not defined $supplementalCategories) {$supplementalCategories = $exifTool->GetValue('SupplementalCategories');}
if (not defined $supplementalCategories) {$supplementalCategories = "";}
if (not defined $labelName1) {$labelName1 = $exifTool->GetValue('LabelName1');}
if (not defined $labelName1) {$labelName1 = "";}
if (not defined $labelName2) {$labelName2 = $exifTool->GetValue('LabelName2');}
if (not defined $labelName2) {$labelName2 = "";}
if (not defined $labelName3) {$labelName3 = $exifTool->GetValue('LabelName3');}
if (not defined $labelName3) {$labelName3 = "";}
if (not defined $labelName4) {$labelName4 = $exifTool->GetValue('LabelName4');}
if (not defined $labelName4) {$labelName4 = "";}
print "Subject:\n------------------------------\n$subject\n\n";
print "Hierarchical Subject:\n------------------------------\n$hierarchicalSubject\n\n";
print "Supplemental Categories:\n------------------------------\n$supplementalCategories\n\n";
print "Label Name 1:\n------------------------------\n$labelName1\n\n";
print "Label Name 2:\n------------------------------\n$labelName2\n\n";
print "Label Name 3:\n------------------------------\n$labelName3\n\n";
print "Label Name 4:\n------------------------------\n$labelName4\n\n";
}
As your code is incomplete, I have to ask: did you make sure to start your script with the following lines?
use strict;
use warnings;
Those two lines are not there to annoy you, they will protect you from simple mistakes you might have made in your code.
IMHO the real problem with your sub listKeywords() is the following line:
my $exifInfo = ImageInfo($filePathXMP);
There are two problems here:
you redefine the variable $exifInfo from a few lines before.
you are not using the OO approach for the 2nd image info.
I think what you intended to write was the following line:
my $exifInfoXMP = $exifToolXMP->ImageInfo($filePathXMP);

Perl Loop Output to Excel Spreadsheet

I have a Perl script, the relevant bits of which are posted below.
# Pull values from cells
ROW:
for my $row ( $row_min + 1 .. $row_max ) {
my $target_cell = $worksheet->get_cell( $row, $target_col);
my $response_cell = $worksheet->get_cell( $row, $response_col);
if ( defined $target_cell && defined $response_cell ) {
my $target = $target_cell->value();
my $response = $response_cell->value();
# Determine relatedness
my $value = $lesk->getRelatedness($target, $response);
# Copy output to new Excel spreadhseet, 'data.xls'
my $workbook1 = Spreadsheet::WriteExcel->new('data.xls');
my $worksheet1 = $workbook1->add_worksheet();
$worksheet1->set_column(0, 3, 18);
my $row = 0;
foreach ($target) {
$row++;
$worksheet1->write( $row, 0, "Target = $target\n");
$worksheet1->write( $row, 1, "Response = $response\n");
$worksheet1->write( $row, 2, "Relatedness = $value\n");
}
}
}
This script uses the Perl modules ParseExcel and WriteExcel. The input data spreadsheet is a list of words under two columns, one labelled 'Target' and the other labelled 'Response.' The script takes each target word and each response word and computes a value of relatedness between them (that's what the
$lesk->getRelatedness
section of code is doing. It is calling a perl module called WordNet::Similarity that computes a measure of relatedness between words).
All of this works perfectly fine. The problem is I am trying to write the output (the measure of similarity, or $value in this script) into a new Excel file. No matter what I do with the code, the only output it will give me is the relatedness between the LAST target and response words. It ignores all of the rest.
However, this only occurs when I am trying to write to an Excel file. If I use the 'print' function instead, I can see all of the outputs in the command window. I can always just copy and paste this into Excel, but it would be much easier if I could automate this. Any idea what the problem is?
You're resetting the value of $row each time to 0.
Problem is solved. I just needed to move the
my $workbook1 = Spreadsheet::WriteExcel->new('data.xls');
my $worksheet1 = $workbook1->add_worksheet();
lines to another part of the script. Since they were in the 'for' statement, the program kept overwriting the 'data.xls' file every time it ran through the loop.

string.find using directory path in Lua

I need to translate this piece of code from Perl to Lua
open(FILE, '/proc/meminfo');
while(<FILE>)
{
if (m/MemTotal/)
{
$mem = $_;
$mem =~ s/.*:(.*)/$1/;
}
elseif (m/MemFree/)
{
$memfree = $_;
$memfree =~ s/.*:(.*)/$1/;
}
}
close(FILE);
So far I've written this
while assert(io.open("/proc/meminfo", "r")) do
Currentline = string.find(/proc/meminfo, "m/MemTotal")
if Currentline = m/MemTotal then
Mem = Currentline
Mem = string.gsub(Mem, ".*", "(.*)", 1)
elseif m/MemFree then
Memfree = Currentline
Memfree = string.gsub(Memfree, ".*", "(.*)", 1)
end
end
io.close("/proc/meminfo")
Now, when I try to compile, I get the following error about the second line of my code
luac: Perl to Lua:122: unexpected symbol near '/'
obviously the syntax of using a directory path in string.find is not like how I've written it. 'But how is it?' is my question.
You don't have to stick to Perl's control flow. Lua has a very nice "gmatch" function which allows you to iterate over all possible matches in a string. Here's a function which parses /proc/meminfo and returns it as a table:
function get_meminfo(fn)
local r={}
local f=assert(io.open(fn,"r"))
-- read the whole file into s
local s=f:read("*a")
-- now enumerate all occurances of "SomeName: SomeValue"
-- and assign the text of SomeName and SomeValue to k and v
for k,v in string.gmatch(s,"(%w+): *(%d+)") do
-- Save into table:
r[k]=v
end
f:close()
return r
end
-- use it
m=get_meminfo("/proc/meminfo")
print(m.MemTotal, m.MemFree)
To iterate a file line by line you can use io.lines.
for line in io.lines("/proc/meminfo") do
if line:find("MemTotal") then --// Syntactic sugar for string.find(line, "MemTotal")
--// If logic here...
elseif --// I don't quite understand this part in your code.
end
end
No need to close the file afterwards.