LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   perl: global replace using hash (https://www.linuxquestions.org/questions/programming-9/perl-global-replace-using-hash-508516/)

WindozBytes 12-08-2006 06:38 AM

perl: global replace using hash
 
The task at hand is to change string1 to string2 in a known list of source files. I've written the perl below to fetch string1 and string2 from a separate file and store them in a hash. The problem is that when I try to make the substitution, the hash values do not seem to match string1 from the source file. (I believe this is the problem since when I hard-code string1 and string2, I get the desired result.) Once changed, the text is written back to the original file, so editing in-place is certainly an option, but the process has to be scripted rather than invoked from a command line.

I've included the lc function when loading the hash, since I know at some point in the future, someone will use a capital letter in a key in the input file, but even without the lc function, the result is the same.

TIA for any assistance.
- - - - - - - - - - - - - - -

#!/usr/bin/perl

use strict ; # enforce good programming rules.
use Cwd ; # include module to allow retrieval of current working directory.


#-------------------------------------------------------------------------------------
# Print begin message.
# ====================

print "Beginning Software Distribution Process: " ; system "date +%Y%m%d-%T" ;
print "\n" ;


#-------------------------------------------------------------------------------------
# Set pkg_name variable.
# ======================

my $dir = getcwd; # get current working directory.
my @dir = split /\//, $dir ; # split full path into directory names and load into array.
$_ = @dir[$#dir] ; # set default variable ( $_ ) to last element of directory array.
s/.tmp$// ; # remove .tmp from default variable.
my $pkg_name = $_ ; # store resulting package name.

print "Package name set to: $pkg_name\n" ;
print "\n" ;


#-------------------------------------------------------------------------------------
# Set directory variables.
# ========================

my $PKG_HOME = $dir ;
print "Package home set to: $PKG_HOME\n" ;
print "\n" ;

#-------------------------------------------------------------------------------------
# Set file variables.
# ===================

my $location = "$PKG_HOME/path.logon" ;
my $file_lst = "$PKG_HOME/objects.lst" ;

#-------------------------------------------------------------------------------------
# Create global variables.
# ========================

my $hash_param ; # individual hash rows.
my $key ; # key for hash_param row.
my $value ; # value for hash_param row.
my $code_module ; # holds name of each code module.

#-------------------------------------------------------------------------------------
# Open parameter file and hash old/new database names, and path to appropriate logon file.
# ========================================================================================

my $success = open FILE_PATH, "<$location" ;
unless ($success) {
&err_open ( $location )
}

while (<FILE_PATH>) {
($key, $value) = split(/:\s*/, $_) ;
chomp ( $key ) ; chomp ( $value ) ;
$hash_param { lc ( $key ) } = $value ;
}

close FILE_PATH ;

#-------------------------------------------------------------------------------------
# Read code module name and call chg_schema subroutine.
# =====================================================

$success = open CODE_MODULE, "<$file_lst" ;
unless ($success) {
&err_open ( $file_lst )
}

while ($code_module = readline CODE_MODULE) {
&chg_schema ( $code_module ) ;
}

close CODE_MODULE ;

exit 0 ;

#-------------------------------------------------------------------------------------
# Subroutine to change code schema.
# =================================

sub chg_schema {

my $file = <$_[0]> ;
print "file: $file\n:" ;
my $success = open FILE_IN, "<$file" ;
unless ($success) {
&err_open ( $file )
}

local $/ ; # enable slurp mode so that entire file is stored in a single variable.

my $lines = lc(<FILE_IN>) ;

print "lines: $lines" ;
close FILE_IN ;

print "old_db: " ; print $hash_param {"old_db"} ; print "\n" ;
print "new_db: " ; print $hash_param {"new_db"} ; print "\n" ;

if (exists $hash_param{"sandbox"}) {
print "old_db value exists\n" ;
} else {
print "no match for old_db\n" ;
}

$success = open ( FILE_OUT , ">$file" ) ;
unless ($success) {
&err_open ( $file )
}

for ( $lines ) {
#$# s/sandbox/production/g ;
s/$hash_param {"old_db"}/$hash_param {"new_db"}/g ; #%#
print FILE_OUT ;
}

close FILE_OUT;
}

#-------------------------------------------------------------------------------------
# Subroutine to process file-open errors.
# =======================================

sub err_open {
system "touch tiv_inst.err" ;
system "date +%Y%m%d-%T" ;
die "File open failure: $_[0]\n$!" ;
}

### File contents listed below; actual files do not include '#' symbol. ###
#-------------------------------------------------------------------------------------
# Contents of path.logon.
# =======================
#old_db: sandbox
#new_db: production
#path: /home/ken/chek

#-------------------------------------------------------------------------------------
# Contents of objects.lst.
# ========================
#test1.vew

#-------------------------------------------------------------------------------------
# Contents of test1.vew.
# ======================
#replace view sandboxv.test1 as
#select * from sandboxt.event;

bigearsbilly 12-08-2006 06:51 AM

substitute in place this for that

Code:

perl -pi.bak -e 's/this/that/g' file1 file2 ...

WindozBytes 12-08-2006 08:54 AM

Thanks for the tip on editing in-place; now I won't need that ugly subroutine. However, I am still left with the original problem that the hash keys do not match a string from the source files. I can get it to work if I read the keys/values into an array, then hash the array, but that seems like such a kluge.

bigearsbilly 12-08-2006 09:16 AM

how is your file organised? key value pairs?
if so slurp into an array and convert to a hash,
easy...

Code:

open IN "< your file";
@array = <IN>;
chomp @array;
%hash = @array;


WindozBytes 12-08-2006 09:57 AM

Still not finding a match; the line for invoking the substitution now looks like this:

`/usr/bin/perl -pi -e "s/$hash_param{old_name}/$hash_param{new_name}/gi" $code_module` ;

Is there something obvious about how I'm invoking the substitution that's precluding a match?

WindozBytes 12-08-2006 10:35 AM

I finally got it to work by using the following:
my $old_name = $hash_param {"old_name"} ; chomp $old_name ;
my $new_name = $hash_param {"new_name"} ; chomp $new_name ;
`/usr/bin/perl -pi -e "s/$old_name/$new_name/gi" $code_module` ;
I may be able to tinker with it and get rid of the extraneous newline character in the hash that was preventing the match without resorting to the temporary names, but I've already spent far too much time with this....

Thanks again for the assist.
Regards,
Ken~

chrism01 12-10-2006 05:20 PM

In the OP, conventionally you'd reverse the order of:

($key, $value) = split(/:\s*/, $_) ;
chomp ( $key ) ; chomp ( $value ) ;

assuming each key-val pair is basically

key : val \n

ie chomp the rec once, then split key/val into vars.


All times are GMT -5. The time now is 10:44 PM.