in reply to Re^9: search and replace strings in different files in a directory (Path::Tiny)
in thread search and replace strings in different files in a directory

I'd like to thank Athanasius for picking up the slack :)

Why was the subroutine called with 6 passed as an argument. Was this just for demonstrating that not only strings but also numbers can be passed to a sub?.

:) To demonstrates that arguments can be passed and they end up in @_ ... so you can lookup @_ in perlvar and read about it :)

Its also so you can resolve the issue you had in Re^2: search and replace strings in different files in a directory (Path::Tiny), something like

#!/usr/bin/perl -- use 5.014; use strict; use warnings; use Path::Tiny qw/ path /; use POSIX(); use autodie qw/ close /; Main( @ARGV ); exit( 0 ); sub Main { #~ my( $infile_paths ) = @_; my( $infile_paths ) = 'C:\temp\test_folder\paths.txt';; my @paths = GetPaths( $infile_paths ); for my $path ( @paths ){ FormerlyMainNowReplaceXmlKids( $path ); } } ## end sub Main sub GetPaths { my @paths = path( shift )->lines_utf8; s/\s+$// for @paths; # "chomp" return @paths; } ## end sub GetPaths sub FormerlyMainNowReplaceXmlKids { #~ my( $directory ) = @_; ## same as shift @_ ## same as shift my $directory = shift; my $date = POSIX::strftime( '%Y-%m-%d', localtime ); my $bak = "$date.bak"; my @xml_files = path( $directory )->children( qr/\.xml$/ ); for my $file ( @xml_files ) { Replace( $file, "$file-$bak" ); } } ## end sub Main sub Replace { my( $in, $bak ) = @_; path( $in )->move( $bak ); my $infh = path( $bak )->openr_raw; my $outfh = path( $in )->openrw_raw; while( <$infh> ) { s{&}{&amp;}g; ## will match more than what you want fix it s{&amp;amp;}{&amp;}g; s{\s>\s}{&gt;}g; s{\s<\s}{&lt;}g; print $outfh $_; } close $infh; close $outfh; } ## end sub Replace

Or (less complete but the sub names is the idea of this idea )

#!/usr/bin/perl -- use strict; use warnings; use Path::Tiny qw/ path /; Main( @ARGV ); exit( 0 ); sub Main { my @dirs = DirsForDiddling( '.../paths.txt' ); DiddleXmlChildren( $_ ) for @dirs; } ## end sub Main sub DirsForDiddling { my( $dirfile ) = @_; my @dirs = path( $dirfile )->lines_utf8; s/\s+$// for @dirs; ## no trailing whitespace return @dirs; } ## end sub DirsForDiddling sub DiddleXmlChildren { my( $directory , $date, $bak ) = @_; $date ||= POSIX::strftime( '%Y-%m-%d', localtime ); $bak ||= "$date.bak"; my @xml_files = XmlChildren( $directory ); for my $file ( @xml_files ) { Diddle( $file, "$file-$bak" ); } } ## end sub DiddleXmlChildren sub XmlChildren { return path( shift )->children( qr/\.xml$/ ); } ## end sub XmlChildren

or more fun with names

sub Main { my @dirs = DirsForDonuts( '.../paths.txt' ); for my $dir( @dirs ){ DonutXmlChildren( $dir ); } } ## end sub Main sub DirsForDonuts { my( $dirfile ) = @_; my @dirs = path( $dirfile )->lines_utf8; s/\s+$// for @dirs; ## no trailing whitespace return @dirs; } ## end sub DirsForDonuts sub DonutXmlChildren { my( $directory , $date, $bak ) = @_; $date ||= POSIX::strftime( '%Y-%m-%d', localtime ); $bak ||= "$date.bak"; my @xml_files = XmlChildren( $directory ); for my $file ( @xml_files ) { Donut( $file, "$file-$bak" ); } } ## end sub DonutXmlChildren sub XmlChildren { return path( shift )->children( qr/\.xml$/ ); } ## end sub XmlChildren

The idea is to have many many many subroutines, and give them names that are memorable... I chose Diddle because RenameMe didn't fit for this problem, and I'm kinda tired of NotDemoMeaningfulName and NotMainMeaningfulNameYouPick is tad long :)

 

Athanasius is doing pretty well :)(thanks) and I'd like to add a little note on why Main/exit, its for ease of writing/debugging/maintaining/documenting the program. The program begins with Main( @ARGV ); and ends after Main completes .

In other languages like C main() is mandatory, but its not mandatory in perl, so perl will let you write interwoven stuff like

Sky( 6 ); my $confusion = 'uhoh'; sub Sky { ... } sub Fall { ... } Fall( 6666666666666 ); ... if( ... ){ ... } ...

and this is very hard to read and maintain, but folks still do it and often struggle debugging this stuff; Main/exit combination is much easier on the brain :)

You can read more about this Main/exit style convention /program template at (tye)Re: Stupid question (and see one discussion of that template at Re^2: RFC: Creating unicursal stars

If you've got more questions, I'll be back :)

Replies are listed 'Best First'.
Re^11: search and replace strings in different files in a directory
by PitifulProgrammer (Acolyte) on Sep 01, 2014 at 12:08 UTC

    Dear Monnks,

    I am getting the strange feeling that my undertaking of writing a "simple" script turns out to be a much larger project than I had anticipated.

    It is a bit frustrating, but we would not be humans if we could not learn from mistakes. Anyway, you kindly offered your help in your last reply and I think I need it (again), since I cannot figure out the current error messages I have been getting

    First message is Cygwin-related (not sure if this is the right place, should I open a new post?).

    What I can figure out is that Cygwin won't install the module, but I have not idea why, since any other installation of perl modules on this machine worked like a charm.

    NE Configuring S/SM/SMUELLER/PathTools-3.47.tar.gz with Makefile.PL Checking if your kit is complete... Looks good Generating a Unix-style Makefile Writing Makefile for Cwd Writing MYMETA.yml and MYMETA.json SMUELLER/PathTools-3.47.tar.gz /usr/bin/perl Makefile.PL -- OK Running make for S/SM/SMUELLER/PathTools-3.47.tar.gz cp lib/File/Spec/OS2.pm blib/lib/File/Spec/OS2.pm cp lib/File/Spec/Mac.pm blib/lib/File/Spec/Mac.pm cp lib/File/Spec/VMS.pm blib/lib/File/Spec/VMS.pm cp lib/File/Spec/Functions.pm blib/lib/File/Spec/Functions.pm cp lib/File/Spec/Epoc.pm blib/lib/File/Spec/Epoc.pm cp lib/File/Spec/Cygwin.pm blib/lib/File/Spec/Cygwin.pm cp lib/File/Spec.pm blib/lib/File/Spec.pm cp Cwd.pm blib/lib/Cwd.pm cp lib/File/Spec/Unix.pm blib/lib/File/Spec/Unix.pm cp lib/File/Spec/Win32.pm blib/lib/File/Spec/Win32.pm Running Mkbootstrap for Cwd () chmod 644 Cwd.bs /usr/bin/perl.exe /usr/lib/perl5/5.14/ExtUtils/xsubpp -typemap /usr/l +ib/perl5/5.14/ExtUtils/typemap Cwd.xs > Cwd.xsc && mv Cwd.xsc Cwd.c gcc-4 -c -DPERL_USE_SAFE_PUTENV -U__STRICT_ANSI__ -g -fno-strict-ali +asing -pipe -fstack-protector -DUSEIMPORTLIB -O3 -DVERSION=\"3.47\" + -DXS_VERSION=\"3.47\" "-I/usr/lib/perl5/5.14/i686-cygwin-threads-64 +int/CORE" -DDOUBLE_SLASHES_SPECIAL=0 Cwd.c /bin/sh: gcc-4: Kommando nicht gefunden. Makefile:367: recipe for target 'Cwd.o' failed make: *** [Cwd.o] Error 127 SMUELLER/PathTools-3.47.tar.gz make -- NOT OK Failed during this command: SMUELLER/PathTools-3.47.tar.gz : make NO cpan[2]>

    I switched to my DOS cmd and thought this would work out, however, when running the script, I got this error message

    c:\dev>perl script.pl Wide character in die at C:/strawberry/perl/site/lib/Path/Tiny.pm line + 1492. Error opendir on '´&#9559;&#9488;Z:/../file.xml': Invalid argument at +script.pl line 57.

    line 57 in the script would be the line with ->children qr/.../(*.xml), which retrieves the xml files:

    sub RetrieveAndBackupXML { #~ my( $directory ) = @_; ## same as shift @_ ## same as shift my $directory = shift; my $date = POSIX::strftime( '%Y-%m-%d', localtime ); #sets cu +rrent date and time to be added to backup file my $bak = "$date.bak"; #date added to the .bak file my @xml_files = path( $directory )->children( qr/\.xml$/ ); for my $file ( @xml_files ) { Replace( $file, "$file-$bak" ); #sub Replace using it's 2 para +meters as defined below } }

    Those xml-files are unicode, so I am wondering why I am getting this wide character message again

    Would be grand if you guys could assist me in this matter, if you need more information about the code or my system let me know.

    Kind regards

    C.
      /bin/sh: gcc-4: Kommando nicht gefunden.

      This means you should install the gcc cygwin package. But unless you really, really need a recent version of File::Spec, don't upgrade File::Spec. It comes with the Perl core distribution and there rarely is a need to upgrade it. I haven't read the previous replies you already got, so there might be a reason to actually upgrade the module, but unless there is a pressing need to do so, I wouldn't.

        Dear Corion,

        Thanks for the hint, I will see to upgrading Cygwin as you pointed out.

        I forgot to mention that my question was related to an error message I got from the shell, i.e.

        File::Spec version 3.4 required--this is only version 3.33 at /usr/lib +/perl5/site_perl/5.14/Path/Tiny.pm line 12.

        So I thought I'd just upgrade the module as the prompt said, but then things got messy (cf. previous post). Or is there another error I failed to spot?

        Thanks a mil in advance for your help

        C.
      &#9559;&#9488;Z:/../file.xml

      Seems like BOM.

      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

        Dear Choroba,

        Thanks for enlighten me, I was not aware of this particular issue. I found out that there is a module for that in perl, but since the code I am using does not use file handles at the crucial part, I am not sure how to use File::BOM correctly. Is there a way to use File::BOM with Path::Tiny or would I have to create a new script?

        Thanks a mil in advance for your comments

        Kind regards

        C.

      I am getting the strange feeling that my undertaking of writing a "simple" script turns out to be a much larger project than I had anticipated.

      Its not that much larger, its just that there is a lot of details :) Its like learning to sing in a new language, there is new sentence structure and new word list ... and you still have to practice hitting your notes :)(reading about it is different than doing it)

      /bin/sh: gcc-4: Kommando nicht gefunden. Makefile:367: recipe for target 'Cwd.o' failed make: *** Cwd.o Error 127

      Like Corion already said, looks like you're missing gcc-4 :)

      Wide character in die at ... Path/Tiny. ... line 57 in the script

      Isn't that wonderfully convenient? I think so (problem detected, error reported informatively)

      So there is a problem with the filename, its got extra stuff. So, to solve the cause you work your way backwards, which function feeds RetrieveAndBackupXML? Which function feeds that function? Is it still called GetPaths? That is where you employ File::BOM, like

      sub GetPaths { use File::BOM; ## my @paths = path( shift )->lines_utf8; my @paths = path( shift )->lines( { binmode => ":via(File::BOM)" } + ); s/\s+$// for @paths; # "chomp" return @paths; } ## end sub GetPaths

      other way without File::BOM

      sub GetPaths { my @paths = path( shift )->lines_utf8; s/\x{feff}//g for @paths; # "de-bom" s/\s+$// for @paths; # "chomp" return @paths; } ## end sub GetPaths

      A tip: if you add use Carp::Always; you will get a stack of error messages, like

      makes it more obvious what sub feeds the dying one

        Dear Anonymous Monk

        Thank you very much for your explanation and your encouraging words. You are right, creating code for a particular task is different than reading the book(s) and going through the exercises.

        I think I still lack this eye for detail and sometimes I am aware of the problem but cannot figure out how to put the solution into code syntax.

        Such was the case with File::Bom. I just did not know how to add to that particular part of the subroutine (not enough practice with modules and objects).

        Thank you also for introducing Carp, I will have a go at it.

        Thanks a mil again for your support, makes the whole a bit easier and it surely is more fun. (This goes for all contributors btw)

        Kind regards

        C.