Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Open Files in Unix

by swartzieee (Initiate)
on Oct 08, 2008 at 01:21 UTC ( #715883=perlquestion: print w/ replies, xml ) Need Help??
swartzieee has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to create a Perl script that will find "cynlogging.properties" files (more than 1 location), Open the file and do a search/replace on the file. i ran the script and it created a new file with the find command for the second part of the script.. So none of the files are being changed.
#!/usr/local/bin/perl print "Making Recommended Logging Changes\n"; #chdir "/opt/tivoli/itcam/was/DC/"; @logging=`find . -name cynlogging.properties`; chomp @logging; print @logging; foreach $prop (@logging) { open (FILE,"<$prop"); @array=<FILE>; close(FILE); foreach (@array) { print @array; $_ =~ s/DEBUG_MIN/WARN/g; } } ####### print "Disable Aspect J And Enable BCI\n"; chdir "/opt/tivoli/itcam/was/DC/runtime/"; @disable=`find . -name toolkit_custom.properties`; foreach $props (@disable) { open (FILE, ">> $props"); @array1=<FILE>; foreach (@array1) { print FILE "am.camtoolkit.gpe.bci.allow.new.fields=true\n"; print FILE "com.ibm.tivoli.itcam.toolkit.ai.createRemeberedObjectField +=true"; $_ =~ s/#am.comtoolkit.gpe.probifier.factory=com.ibm.tivoli.itcam.tool +kit.ai.bci.engine.BCIEngineProbifierFactory/am.comtoolkit.gpe.probifi +er.factory=com.ibm.tivoli.itcam.toolkit.ai.bci.engine.BCIEngineProbif +ierFactory/; } close(FILE); } ####### print "Recycle Configured JVM's\n"; exit 0;

Comment on Open Files in Unix
Download Code
Re: Open Files in Unix
by ikegami (Pope) on Oct 08, 2008 at 01:27 UTC

    ( The OP is no longer what it was when I replied. The code snippet was changed, and a second code snippet was added. )

    There are no syntax errors.

    >perl -c script.pl script.pl syntax OK

    But that doesn't mean it does what you want it to do.

    @logging='find . -name cynlogging.properties';
    should be
    @logging=`find . -name cynlogging.properties`;

    And you need to remove the newlines returned by find by adding
    chomp @logging;

    Finally, you never write your changes to the file.

    Update: Missed one.

    Your inner loop modifies $prop repeatedly, but the loop variable is the default $_.
    $prop =~ s/DEBUG_MIN/WARN/g;
    should be
    $_ =~ s/DEBUG_MIN/WARN/g;
    which is the same as just
    s/DEBUG_MIN/WARN/g;

Re: Open Files in Unix
by oko1 (Deacon) on Oct 08, 2008 at 03:29 UTC

    Rather than using an external, non-portable program, you can use File::Find - it comes with Perl, and works pretty well. It also seems like you were trying to imitate the functionality of Tie::File without actually using it - so that didn't work either. Here's an example of how you might use those two to do what you want:

    #!/usr/bin/perl -w use strict; use File::Find; use Tie::File; find(\&wanted, '/opt/tivoli/itcam/was/DC/'); sub wanted { return unless /cynlogging.properties/; tie my @file, 'Tie::File', $_ or die "$_: $!\n"; s/DEBUG_MIN/WARN/g for @file; untie @file; }

    The second script is close enough to the first one that I'm going to take the easy way out and say "Solution is trivial, and left as an exercise for the student." :)


    --
    "Language shapes the way we think, and determines what we can think about."
    -- B. L. Whorf
      Rather than using an external, non-portable program...

      But 'find' is quite portable. Furthermore, the OP mentioned in his title he was using Unix. 'find' has not only been ported to all Unix flavour, it's also found on (almost) any Unix system.

        Is it? Please try "find -iname '*foo'" or "find -regextype posix-egrep '[abc]\.html'" on, say, a Solaris system - or one with OS/X. A plain "find" (i.e., no options) would serve the OP's purpose - but it is not portable, and its use in scripts should be discouraged.


        --
        "Language shapes the way we think, and determines what we can think about."
        -- B. L. Whorf
Re: Open Files in Unix
by swartzieee (Initiate) on Oct 08, 2008 at 17:21 UTC
    I just tested the script, it runs with no errors but non of the file changes are made. what could be wrong?
Re: Open Files in Unix
by swartzieee (Initiate) on Oct 08, 2008 at 17:39 UTC
    #!/usr/local/bin/perl print "Making Recommended Logging Changes\n"; #chdir "/opt/tivoli/itcam/was/DC/"; @logging=`find . -name cynlogging.properties`; chomp @logging; print @logging; foreach $prop (@logging) { open (FILE,"<$prop"); @array=<FILE>; close(FILE); foreach (@array) { print @array; $_ =~ s/DEBUG_MIN/WARN/g; } } ####### print "Disable Aspect J And Enable BCI\n"; chdir "/opt/tivoli/itcam/was/DC/runtime/"; @disable='find . -name toolkit_custom.properties'; foreach $props (@disable) { open (FILE, ">> $props"); @array1=<FILE>; foreach (@array1) { print FILE "am.camtoolkit.gpe.bci.allow.new.fields=true\n"; print FILE "com.ibm.tivoli.itcam.toolkit.ai.createRemeberedObjectField +=true"; $_ =~ s/#am.comtoolkit.gpe.probifier.factory=com.ibm.tivoli.itcam.tool +kit.ai.bci.engine.BCIEngineProbifierFactory/am.comtoolkit.gpe.probifi +er.factory=com.ibm.tivoli.itcam.toolkit.ai.bci.engine.BCIEngineProbif +ierFactory/; } close(FILE); } ####### print "Recycle Configured JVM's\n"; exit 0;

      You still haven't fixed the quoting to backticks on your second find command like ikegami pointed out in the very first reply.

      Addendum: And if you bothered checking the return value from open on the next line and printing out the error message you might have noticed this yourself . . .

      Continuing: And trying to read from a filehandle you've opened for writing (well, we'll presume that you eventually correct the other errors to that point) with the line @array1 = <FILE> after the unchecked open is meaningless. You either need to open the file for reading and writing and do some seek magic to rewind it, or (more simply) write the updated contents to a new file and rename over the original.

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

      I personally believe that shell scripts should be written in shell, and Perl scripts in perl. Now, the distinction is not always clear, and there are corner cases, but yours is well close to the first category, to say the least: in fact someone suggested you inside-out solutions, namely, instead of a Perl program running find(1) a find(1) command running perl, and perl may be substituted with sed(1) there.

      #!/usr/local/bin/perl

      You're missing the single two most important lines for your program:

      use strict; use warnings;

      Others would add diagnostics to the list, but I regard it as "something more" whereas the former two are the very strictly close to fundamental, and I would only avoid them in onliners and in the simplest scripts.

      chomp @logging; print @logging;

      Do you really want to print them like that? It will look awful!

      open (FILE,"<$prop");

      Here and for the rest of your program, do a favour to yourself and use the three args form of open, possibly along with "lexical handles" (which will dispense you from the need of explicit close's) and most importantly, checking for success. If you're lazy and don't want to check individual open()'s, then you can use Fatal instead.

      foreach (@array) { print @array;

      Do you really want to print the same string for each element of @array? (What an awful name for a variable, BTW: it's neither descriptive nor short enough to be used instead of a descriptive one...) Sorry: I now see it won't print "the same string" for all elements, but indeed it is so strange a logic that got me confused, and this is the reason why I stroke the text before rather than simply deleting it. Anyway, clarity is in the eye of the beholder, they say...

      $_ =~ s/DEBUG_MIN/WARN/g; }

      This is a specific idiodincrasy of mine: while perfectly valid Perl, it doesn't make much sense in that you should either take full advantage of $_ being a pronoun, and the topicalizer, thus used implicitly and by default by many functions and operators or use the binding operator =~ on a generic variable.

      @disable='find . -name toolkit_custom.properties';

      Here, you're thinking of using the backticks as above, but you made a typo. In absence of the checks that I and others, suggested you, you won't even notice. Which is the reason why we suggested you to do them in the first place.

      foreach $props (@disable) { open (FILE, ">> $props"); @array1=<FILE>;

      This is the most serious error you've made thus far. You're opening a file for appending and then you're attempting to read from it.

      All in all, if I understand the logic you're after from your broken code, I presume you may be interested in the -i cli switch, or in the ^I special variable, or in reproducing their effects "manually," which you don't, as of now. So no surprise "it doesn't work:" you can't expect the effect of a s/// to propagate to a file only because you read the variable you're applying it to from that particular file.

      --
      If you can't understand the incipit, then please check the IPB Campaign.
Re: Open Files in Unix
by swartzieee (Initiate) on Oct 08, 2008 at 18:13 UTC
    I did fix the second find tick's. After the change i reran the script and it created a new file with the find command.. So non of the files are being changed.
Re: Open Files in Unix
by superfrink (Curate) on Oct 08, 2008 at 19:16 UTC
    I would use something like the following command line.
    find -name cynlogging.properties -exec perl -p -i.backup -e 's/search/ +replace/g' {} \;
    For example:
    $ mkdir x $ cd x $ mkdir b $ date > asdf $ date > b/asdf $ cat asdf Wed Oct 8 13:11:35 MDT 2008 $ find . -name asdf -exec perl -p -i.backup -e 's/1/XXX/g' {} \; $ cat asdf Wed Oct 8 XXX3:XXXXXX:35 MDT 2008 $ cat b/asdf Wed Oct 8 XXX3:XXXXXX:37 MDT 2008 $ cat asdf.backup Wed Oct 8 13:11:35 MDT 2008
      to run as a perl script do i do system ("find -name cynlogging.properties -exec perl -p -i.backup -e 's/search/ +replace/g' {} \");

        I personally believe that if this is a question, then it should be marked with... a question mark. Anyway, the answer is yes, or at least that is a possible way to do it. (Except that, as a minor point, you should quote the backslash.) But more importantly why, precisely, should you run the above line "as a perl script?" The whole point was that probably a single find(1) command is better suited to your need than a whole Perl program. (Although one may consider there that perl is called multiple times in the second case, and this includes a overhead... probably a completely irrelevant consideration, in this particular situation - and there are simple cures, anyway.)

        --
        If you can't understand the incipit, then please check the IPB Campaign.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://715883]
Approved by ikegami
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (19)
As of 2014-10-01 19:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    What is your favourite meta-syntactic variable name?














    Results (35 votes), past polls