Maire has asked for the wisdom of the Perl Monks concerning the following question:

Good morning Monks,

I have a large folder of text files, and I want to substitute all instances of a certain string within those files with another string (essentially every time the word “end” appears, I want to start a new line).

To do this, I thought it would be safer to use a script that copies the files to a new folder before it modified them. After a bit of Googling, I found a Perl script (created by durden_tyler and uploaded to https://www.unix.com/302318333-post5.html) which, with a couple of modifications, allows me to do just this.

#!perl -w # Script to process all *.txt files in current directory and put the o +utput # in the corresponding *.txt.new files in the current directory again. my $indir = 'C:\Users\li\test'; # the input directory name my $outdir = 'C:\Users\li\test2'; # the output directory name my $i = 0; # loop index my $infile; # the input file name my $outfile; # the output file name while (defined($infile = glob($indir."\\*.txt"))) { # loop + through the txt files in directory $indir printf("(%d)\tNow processing file => %s\t",++$i,$infile); $outfile = $outdir."\\".substr($infile,rindex($infile,"\\")+1); # n +ame the output file open (IFILE, "<$infile") or die "Can't open $infile: $!"; # open + input file for reading open (OFILE, ">$outfile") or die "Can't create file: $!"; # crea +te output file for writing while (<IFILE>) { # loop through contents of the input file my @lines = <IFILE>; my @newlines; foreach(@lines) { $_ =~ s/<\/end>/<\/end>\n/g; push(@newlines,$_); print OFILE $_; } close(IFILE) or die "Can't close $infile: $!"; # clos +e input file close(OFILE) or die "Can't close $outfile: $!"; # clos +e output file printf("Output file => %s\n",$outfile); } }

The only problem is that this process (obviously) alters the original “date modified” Windows timestamps (that are displayed in File Explorer) for the files. This is unfortunate because the timestamps, at the moment, are one of the key ways that I’m keeping track of the large amount of data I’ve got.

Is there any way that I can still substitute the string within each file without losing the original date modified timestamp?

Thanks a lot!

Replies are listed 'Best First'.
Re: Maintaining date modified timestamp when copying files (updated x2)
by haukex (Archbishop) on Oct 29, 2017 at 09:48 UTC
    Windows timestamps

    Quoting myself from Re: Change create file date:

    A quick search on CPAN reveals that Win32API::File::Time may be able to help you. From its synopsis:

    use Win32API::File::Time qw{:win}; ($atime, $mtime, $ctime) = GetFileTime ($filename); SetFileTime ($filename, $atime, $mtime, $ctime);

    (Unfortunately still untested.)

    Update:

    the timestamps, at the moment, are one of the key ways that I’m keeping track of the large amount of data I’ve got

    Actually, as you're discovering yourself, this is dangerous, I'd strongly recommend you don't rely on the filesystem to keep track of that information, at the very least store the date/time information in a separate simple text file. Update 2: The following will take the list of files in the current directory (excluding those beginning with a dot) and output a tab-separated list of filename, ctime, mtime, and atime (if available). You can change the glob expression "*" to match specific files if you like.

    perl -MFile::Glob=bsd_glob -le '$,=qq(\t);print$_,(stat)[10,9,8]for bs +d_glob(q(*))'

    (You may need to change the quotes, I'm not on Windows at the moment.)

      Thanks for your help! I've installed the module, and I'm just playing about with it now to see if I can get it to work on my data. I will edit my post to verify the solution if I have any success. And thank you so much for the script to back-up the metadata for my work! I'd tried creating something similar myself, but I wasn't using the glob function and was thus not having much luck.
Re: Maintaining date modified timestamp when copying files
by Laurent_R (Canon) on Oct 29, 2017 at 11:32 UTC
    The best might be to include the creation or last modification time stamp into the name of the files before you proceed to modify the files, so that you don't rely on something that is prone to changes.

    Otherwise, using bash under Windows (for example Git Bash, or Cygwin) enables you use the touch Unix command in order to modify the last modification time to whatever value you wish.

        Thanks!
      Thank you! Funnily enough, I have recently installed the bash shell for Windows 10 because I heard that it is good for file management/modification etc., so this will give me a chance to have a play around with it. Thanks!