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

Hi, I'm trying to get each XML file's name in a directory, then put the file's name in that XML file under an element <asset-id>, but how come I can have the output displayed on the screen, using ./myPerl.pl, but I don't know how to write the output file using "open (FILE,">$directory/$_") ", I always get an empty XML file after I add the ">" in the line. I tried to put a line "print FILE $_;" at the end of the While loop, but it doesn't work. I know that I need to output the FILE, but how? Can anyone help?
my $directory = '/usr/local/XML'; opendir(DIR,$directory); my @files = grep { $_ ne '.' && $_ ne '..' } readdir DIR; closedir(DIR);<BR> foreach(@files){ open (FILE,"$directory/$_") my $files="$_"; while(<FILE>){ print $_; if ($_=~/(<asset-id)(.*?)>/){ print "\t\t <local-id>$files</local-id>\n"; } } close(FILE); }

Replies are listed 'Best First'.
Re: output can be displayed in screen, but not in output file
by kyle (Abbot) on Nov 28, 2007 at 04:28 UTC

    Welcome to the Monestary, happyrainb.

    You're trying to modify a file as you're reading it.

    You might want to use File::Inplace for this, or maybe Tie::File. If you'd like to do this without modules, you'd probably have to read the whole file in first, modify the variable that has it, and then write it all out again.

Re: output can be displayed in screen, but not in output file
by tachyon-II (Chaplain) on Nov 28, 2007 at 07:34 UTC

    You can do this task all sorts of ways in perl. It is often done using what is know as "inplace editing". It is in the FAQ which are worth a look if you are new to perl. Inplace Editing shows several idioms and one liners. The classic is:

    perl -pi.bak -e 's/OLDSTRING/NEWSTRING/g' FILELIST

    Taking the code you have, adding some error checking and rationalising your matching regex where you capture things into $1 and $2 but do nothing with them (untested):

    for my $file (@files){ open IN,"$directory/$file" or die "Can't read $directory/$file Error: $!\n"; open OUT,">$directory/$file.out" or die "Can't write $directory/$file.out Error: $!\n"; while(<IN>){ chomp; # remove newline so new data on same (?correct?) line print OUT $_; print OUT "\t\t <local-id>$file</local-id>" if /<asset-id/; print OUT "\n"; } close IN; close OUT; # now unlink IN and rename OUT to IN if desired. # warning unlink will delete the original file # unlink "$directory/$file" or die $!; # rename "$directory/$file.out", "$directory/$file" or die $!; }

    This is not an elegant of perlish way of doing it but should get you heading in the right direction.

      Thank you very much! It works perfectly. I will keep learning from here!

        To prevent unwanted disaster I suggest the first step should be to rename the file file.txt -> file.txt.bak. Then read this .bak file and write out the new file, that way you retain the original in case you accidentally destroy the data, which is easy enough to do.