jason dancks
jason dancks

Reputation: 1142

perl: File::Copy: no such file or directory error on reading existing file

I'm trying to download ruby gems listed in several example rails projects I downloaded via bundle install with the latest version of ruby installed through RVM, and I'm following the directions here to properly downloads the gems listed in the bundler files. I thought I'd speed up the process with this perl script: (Not quite comfortable with bash yet):

#!/usr/bin/perl
use File::Copy qq(copy);

use strict;
use warnings;

my @files = `ls`;
foreach my $dir (@files)
{
    chomp $dir;
    if( -d $dir)
    {
        print "\n\n\tabout to enter $dir\n\n\n";
        print `cd "$dir"`;
        system("echo \"2.2.0\" > .ruby-version");
        system("echo \"$dir\" > .ruby-gemset");
        copy("Gemfile", "tmp.save") or die "copy: $!\n";
        open(RD,"<tmp.save") or die "$dir: tmp.save: $!\n";
        open(WR,">Gemfile") or die "$dir: Gemfile: $!\n";
        print WR <RD>;
        print WR "\n";
        print WR "ruby \'2.2.0\'";
        print WR "\n\n";
        while(<RD>) { print WR $_; print WR "\n"; }
        close(RD); close(WR);
        print `cd ..`; 
        print `cd "$dir"`;
        print `bundle install`;
        print `cd ..`;
    }
}

error is:

copy: No such file or directory

The file clearly exists these projects are presumably created with rails <name> command. Why would this happen and how do I fix it?

Upvotes: 0

Views: 1226

Answers (1)

ThisSuitIsBlackNot
ThisSuitIsBlackNot

Reputation: 24063

When you invoke an external command with system or backticks, you spawn a new process. That process gets its own environment, which is not shared with the parent process or with other children:

system('pwd'); # /foo
system('cd "/bar"');
system('pwd'); # still /foo

(Note that if you're not actually storing the output of a command, it's preferable to use system instead of backticks.)

This means that when you `cd "$dir"`, your Perl script's working directory isn't changing. To fix, use native Perl commands instead of invoking shell commands.

Here's a rough example (untested):

use strict;
use warnings;

use File::Copy;

my $parent_dir = 'foo';

opendir my $dh, $parent_dir or die "opendir failed on '$parent_dir': $!";

my @subdirs = map { "$parent_dir/$_" }
              grep { $_ !~ /^\.\.?$/ && -d "$parent_dir/$_" } readdir $dh;

foreach my $subdir (@subdirs) {
    my $source = "$subdir/Gemfile";
    my $target = "$subdir/tmp.save";

    if (-f $source) {
        copy $source, $target or die "copy failed: $!";
    }
}

Upvotes: 4

Related Questions