Script to conditionally copy and modify file
New here? Learn about Bountify and follow @bountify to get notified of new bounties! x

A perl script in a .pl file. (Or python. Perl is $35, python is $25)

that takes a single command line parameter, which is the relative location of a file in a subdirectory of the current directory

The code will copy the specified file to a different file whose name and path is nearly the same as the source file except that the destination path has "target/" prepended.

Ex. if the source file is specified:

src/myfile.txt >>> target/src/myfile.txt

libs/loops.lib >>> target/libs/loops.lib

/letters/myfile.txt >>> (((error. only relative paths are accepted. rc=4)))

(((unspecified))) >>> (((error. user must specify a parameter. rc=6)))

src/file_that_does_not_exist.txt >>> (((error. the source file must exist. rc=7)))

subdir/../myfile.txt >> (((error. we do not accept source paths that include .. . rc=8)))

The copy will only happen if the target file does not exist or is older than the source file

The target file will not be an exact copy of the source file. Instead, all occurrences of the string $(mycat) will be replaced with Garfield in the target file. Otherwise the files should be identical.

If the target directory does not exist, it should be created.

This code must be original code and not encumbered by IP restrictions and must be suitable for use in open source projects. It must not have a GPL license. MIT or BSD license is acceptable.

awarded to gabrielsimoes

Crowdsource coding tasks.

1 Solution

This should do:

#!/usr/bin/perl -w

use strict;
use autodie;

if ($#ARGV + 1 != 2) { print STDERR "error. user must specify a parameter.\n"; exit 6; }
if (! -f $ARGV[0]) { print STDERR "error. the source file must exist.\n"; exit 7; }
if ($ARGV[0] =~ /^\//) { print STDERR "error. only relative paths are accepted.\n"; exit 4; }
if ($ARGV[0] =~ /\.\.\//) { print STDERR "error. we do not accept source paths that include.\n"; exit 8; }

use File::Path;
use File::Basename;
use File::stat;

my $from = $ARGV[0];
my $to = $ARGV[1] . "/" . dirname($from);
my $tofile = $to . "/" . basename($from);

if (! -d $from) { mkpath($to); }

if (! -f $tofile || stat($from)->mtime > stat($tofile)->mtime) {
    open my $input, '<', $from;
    open my $output, '>', $tofile;
    while (<$input>) {
        print $output $_;
    close $input;
    close $output;

Let me know if you need any changes.

If you don't want the script to print error messages, change the beginning to this

#!/usr/bin/perl -w

use strict;
use autodie;

if ($#ARGV + 1 != 2) { exit 6; }
if (! -f $ARGV[0]) { exit 7; }
if ($ARGV[0] =~ /^\//) { exit 4; }
if ($ARGV[0] =~ /\.\.\//) { exit 8; }
Don't forget to include the code that will convert $(mycat) to Garfield during the copy. And also the code to only do the copy if the source is newer than the target.
jasonnet 12 months ago
Sorry, completely overlooked this. Will do. By the way, do you want the error messages?
gabrielsimoes 12 months ago
Also, by $(mycat) you mean a variable or a string like "$(mycat)"?
gabrielsimoes 12 months ago
I mean if the source file contains "today $(mycat) meowed all night" the target file should contain "today Garfield meowed all night".
jasonnet 12 months ago
Sorry for too many edits, but now it should work correctly.
gabrielsimoes 12 months ago
Nice job. Quickly done, concise and correct. Thanks.
jasonnet 12 months ago