Search code examples
regexbashperlabsolute-path

Bash & Perl script to convert relative paths to absolute paths


I have a top level dir path and I want to convert all the relative paths to absolute paths existing in all files inside this directory recursively. e.g. I have this dir structure:

$ tree
.
|-- DIR
|   |-- inner_level.ext1
|   `-- inner_level.ext2
|-- top_level.ext1
`-- top_level.ext2

Content of top_level.ext1:

../../a/b/c/filename_1.txt
../../a/d/e/filename_2.txt

Assume the top level dir path is /this/is/the/abs/dir/path/

Want to convert the content of top_level.ext1 to:

/this/is/the/abs/a/b/c/filename_1.txt
/this/is/the/abs/a/d/e/filename_2.txt

Content of top_level.ext2:

cc_include+=-I../../util1/src/module1/moduleController -I../../util/src/module1/module2Controller;
cc_include+=-I../../util2/src/module2/moduleUtility;

Want to convert the content of top_level.ext2 to:

cc_include+=-I/this/is/the/abs/util1/src/module1/moduleController -I/this/is/the/abs/util/src/module1/module2Controller;
cc_include+=-I/this/is/the/abs/util2/src/module2/moduleUtility;

Also, want to apply this same conversion over the files inside DIR.

e.g. Content of DIR/inner_level.ext1:

../../../a/b/c/filename_1.txt
../../../a/d/e/filename_2.txt

Want to convert the content of DIR/inner_level.ext1 to:

/this/is/the/abs/a/b/c/filename_1.txt
/this/is/the/abs/a/d/e/filename_2.txt

Same for the DIR/inner_level.ext2 also.

Have written this two scripts.

Conversion of top_level.ext1 is working successfully.

file_manager.sh:

#!/usr/bin/bash
file='resolve_path.pl'
basedir='/this/is/the/abs/dir/path'

run_perl(){
    echo -e "\n File getting modified: $1"
    cp $1 tmp.in
    perl $file 
    mv tmp.out $1
    rm tmp.in
}

find $basedir -type f |while read inputfile
do 
    run_perl $inputfile
done

resolve_path.pl:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use 5.010;
use Switch;

#******************************************************
#       Set-up Directory And Input/Output File Names
#******************************************************
our $in_file  = glob('tmp.in');
my $out_file1 = 'tmp.out';
print "Input file: $in_file\n";

#************************************
#       Local and Global Variables
#*************************************
my $current_path = "/this/is/the/abs/dir/path";
my $temp_path = $current_path;

#************************************
#       Open Read and Write File
#************************************
open(READ, $in_file) || die "cannot open $in_file";
open(WRITE, ">$out_file1") || die "cannot open $out_file1";


#******************************************************
#       Read The Input [*.out] File Line By Line
#******************************************************
while (<READ>) {
    if(/^(\.\.\/){1,}(\w+\/)*(\w+).(\w+)/){
      my $file_name = $3;
        my $file_ext  = $4;

        my @count = ($_ =~ /\.\.\//g);
        my $cnt = @count;

        my @prev_dir = ($_ =~ /\w+\//g);
        my $prev_dir_cnt = @prev_dir;
        my $file_prev_dir = join('', @prev_dir);

        $temp_path = $current_path;
        for(my $i=0; $i<$cnt; $i++){
            if($temp_path =~m/(\/.*)\/\w+/){
                $temp_path = $1;
            }
        }

        print WRITE "$temp_path"."\/"."$file_prev_dir"."$file_name"."\."."$file_ext"."\n";

    } else {
        print WRITE "$_";
    }
}

Issues I am facing:

  1. No conversion is applied over top_level.ext2 & DIR/inner_level.ext2 as my Perl script is not parsing properly for ../es (i.e. cc_include+=-I is coming at the beginning).

  2. conversion from relative path to absolute path is not working properly for DIR/inner_level.ext1 and a wrong path is getting appended.

It would be helpful if someone can suggest expected changes in my scripts to solve the above said two issues.


Solution

  • Why the 2 scripts? That's inefficient.

    Perl is perfectly capable of retrieving the list of files and has modules which simplifies that process as well as modules to parse and alter the paths.

    File::Find - Traverse a directory tree.

    File::Find::Rule - Alternative interface to File::Find

    File::Basename - Parse file paths into directory, filename and suffix.

    File::Spec - portably perform operations on file names