Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

if or die!

by wcj75019 (Acolyte)
on Mar 01, 2008 at 16:30 UTC ( [id://671389]=perlquestion: print w/replies, xml ) Need Help??

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

This node falls below the community's threshold of quality. You may see it by logging in.

Replies are listed 'Best First'.
Re: if or die!
by Corion (Patriarch) on Mar 01, 2008 at 16:41 UTC

    Maybe the answers in I just want IF, OR, OR not every one or if elsif elsif prints all three. can help you?

    At least show the courtesy to link to your older nodes if you're going to make a new toplevel node about the same problem. You could also spend some more time at explaining what you want your program to do. In separate, short but still coherent sentences. Maybe. Instead. Of using. Punctuation where. *** It does not make. Sense.

    Also, providing some sample input and output makes it easier for us to see where your problem is. Also, maybe even provide the output you want as well - this gives us even more to work with.

    As to your problem, I don't understand what you're trying to do. But the following line makes no sense:

    ($line =~ m/'syslogd'\)/);

    What is this line supposed to do? Why is it in your program?

    Looking further, the whole block makes no sense to me:

    } else { ($line =~ m/'syslogd'\)/); my $newline = $. + 3; $newline = $bgs; print OUT $newline; next; }

    What is it supposed to do? How does it differ from the following?

    print OUT $bgs; next;
      I would gladly link these together. I don't know how to do that. No, the answer wasn't in any of those postings. I did get some things that I added. But, the fundamental piece is still not working.
      else { ($line =~ m/'syslogd'\)/); my $newline = $. + 3; $newline = $bgs; print OUT $newline; next;
      If bgs isn't in the file. else go to syslogd. then after 3 lines. add the here document $bgs. Print to OUT file. I can't get it to work. If bgs isn't there. How do I add $bgs after the syslogd.

        I'm sorry, but I still don't understand you. English is not my first language, maybe it's not your first language either - please try to phrase your problem in longer sentences that do not start with "Else".

        I'm trying to rephrase your problem as I interpret it - please correct me if I get it wrong:

        1. You want to print some stuff to the output file if it does not contain the word "bgs".
        2. You want that output to into the third line after the word "syslogd" (which occurs only once in the file anyway).

        Is that correct?

        To attack this problem, let's just reduce all we do to solving this small part and disregard all surrouding stuff. Once we've solved the small part, we can move towards solving the integration into your big program.

        For simplicity, let's assume we have the following input file:

        This is a test file. Here comes the line we want: 'syslogd') You see it? It was two lines ago. And before this line we want to output the other stuff.

        And from how I interpret your task, this is what you want as output:

        This is a test file. Here comes the line we want: 'syslogd') You see it? It was two lines ago. 'bgs') /usr/bin/su - patrol /usr/adm/best1_default/bgs/scripts/best1collect -q>>\$LOG 2>>\$LOG ;; And before this line we want to output the other stuff.

        See how writing down what you have and what you want makes the problem much clearer?

        Now, on to your code:

        First, the line

        ($line =~ m/'syslogd'\)/);
        makes no sense at all. It just checks whether the current line contains "'syslogd')", but then ignores that knowledge completely.

        The line

        my $newline = $. + 3;

        Only assigns to $newline the number of the current line plus three. It does not advance the current file or anything.

        The lines

        $newline = $bgs; print OUT $newline; next;

        print out

        'bgs') /usr/bin/su - patrol /usr/adm/best1_default/bgs/scripts/best1collect -q>>\$LOG 2>>\$LOG ;;

        immediately, instead of waiting some more lines.

        You could have told us that directly - by displaying what output you get.

        Anyway, take a look at the following program, which reads from the DATA filehandle and see if you understand how it does what it does:

        #!/usr/bin/perl -w use strict; my $bgs = <<'HERE'; 'bgs') /usr/bin/su - patrol /usr/adm/best1_default/bgs/scripts/best1collect -q>>$LOG 2>>$LOG ;; HERE # Read the whole file into memory. This makes things easier # for us. Later we can use Tie::File to treat the file # as an array. my @lines = <DATA>; my $saw_bgs; for my $line (@lines) { if ($line =~ /bgs/) { $saw_bgs++; print "I saw 'bgs' in line >$line<\n"; }; }; if (! $saw_bgs) { print "I did not see 'bgs' at all.\n"; }; open my $out, ">", 'test.out' or die "Couldn't create 'test.out': $!"; # Output our file, adding $bgs if necessary my $print_bgs; # Counter for when to print $bgs for my $line (@lines) { if ($line =~ /'syslogd'\)/) { $print_bgs = 2; # Three lines to go } elsif (defined $print_bgs and $print_bgs > 0) { $print_bgs--; # another line done } elsif (defined $print_bgs and $print_bgs == 0) { print {$out} $bgs; # Yay, we counted three lines, so now we +can output $bgs } else { # Nothing to do, just a normal line }; print {$out} $line; }; __DATA__ This is a test file. Here comes the line we want: 'syslogd') You see it? It was two lines ago. And before this line we want to output the other stuff.
Re: if or die!
by chromatic (Archbishop) on Mar 01, 2008 at 19:56 UTC
    Only problem: It fills every file with the stinkin here document. over and over.

    Yeah, it does. That's what your continue block does, if the conditional is true. That's what your else block does, if the conditional is not true. You need to stop commenting and uncommenting code and randomly adding and moving around code, because you're just making a mess and confusing yourself.

    Here is your first problem:

    } else { ($line =~ m/'syslogd'\)/); my $newline = $. + 3; $newline = $bgs; print OUT $newline; next; }</c>

    This block only executes if the current line does not contain bgs. That's probably most lines of the file.

    The regular expression does nothing. It's dead code. Delete it.

    The next line declares the variable $newline and assigns it a value. This is nearly dead code, because the subsequent line overwrites that value with the heredoc, which gets printed in the next line. Control flow then skips to the continue block, which prints the current line.

    You're not going to get this to work until you sit down, write out what you want to accomplish, list the necessary steps in order, and then translate that to code. Please do that; you'll save yourself a lot of time and trouble.

Re: if or die!
by shmem (Chancellor) on Mar 01, 2008 at 17:57 UTC
    if or die!

    Well, it's die this time round, I guess.

    Your re-wording is bad, since it doesn't provide any further information. Here's my rephrasing, from what I can read from your code. Please correct that and post your correction.

    Hello monks,

    I have to munge shell scripts.

    I have a list of files collected in a file called 'sys.sh'. These shell script files contain a case...esac statement, which I have to check for the occurrence of a 'bgs' case. If it is not in there, I want to write that case statement right after the 'syslogd' case branch. I open each file for output, then for input, and try to get at the relevant cases. I have difficulties getting at the relevant lines in those files and don't know how to change a complete case branch in one go. What am I missing?

    to which I would respond:

    See the documentation for open, or read perlopentut. If you open a file for output, you clobber it. A subsequent open for input just opens an empty file. You might want to use inplace edit, open it for update (+<) or write to a temporary file which you rename to the original after having closed the filehandle for writing.

    You could slurp in the file in one go and do a match like /('bgs\).*?;;)/s to have the complete bgs case branch in $1 - read perlretut and perlre if things are unclear here.

    You could also go through each file line by line, in which case you have to carry state variables you set and unset at the beginning and end of those case branches. You could weed out any eventual 'bgs' branches (by just ignoring them) and print your new 'bgs' branch right after the 'syslogd' branch, or before the closing 'esac' if it hasn't already been printed.

    update:

    One possible solution (if I understand rightly what you want to achieve):

    foreach my $sh (@sh_f) { local $/ = ''; # slurp mode open IN, '<', $sh # really? or is it "$cf_dir/$sh" ? or die "Can't open '$sh' for input: $!\n"; open OUT, '>', "$cf_dir/$sh.tmp" or die "Can't write '$cf_dir/$sh.tmp': $!\n"; $_ = <IN>; s/^\s*'bgs'\).*?;;//msg; s/^(\s*'syslogd'\).*?;;/$1\n$bgs/ms; print OUT; close OUT or die "Can't close filehandle OUT properly: $!\n"; rename "$cf_dir/$sh.tmp", $sh; # if appropriate }

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Dear Shmem, I like that. It is simple. Thanks.
      #!/usr/bin/perl -w use strict; my $agent = "best1agent_start"; my $bgs=<<HERE; 'bgs') /usr/bin/su - patrol /usr/adm/best1_default/bgs/scripts/best1collect -q>>\$LOG 2>>\$LOG ;; HERE my $collect = " /usr/bin/su - patrol /usr/adm/best1_default/bgs/scripts/best1collect -q>>\$LOG 2>>\$LOG\n" +; my $cf_dir = "/root/sysedge/cf_files"; #my $cf_dir = "/export/home/f358118/sysedge"; open SH_FILES, "sys.sh" or die "Error: $!"; my @sh_f=<SH_FILES>; close SH_FILES; foreach my $sh (@sh_f) { local $/ = ''; # slurp mode open IN, '<', $sh # really? or is it "$cf_dir/$sh" ? or die "Can't open '$sh' for input: $!\n"; open OUT, '>', "$cf_dir/$sh.tmp" or die "Can't write '$cf_dir/$sh.tmp': $!\n"; $_ = <IN>; s/^\s*'bgs'\).*?;;//msg; s/^(\s*'syslogd'\).*?;;/$1\n$bgs/ms; print OUT; close OUT or die "Can't close filehandle OUT properly: $!\n"; rename "$cf_dir/$sh.tmp", $sh; # if appropriate }
        Unmatched ( in regex; marked by <-- HERE in m/^( <-- HERE \s*'syslogd'\).*?;;/ at b.t line 27

        Yeah, closing paren missing. Oops :-)

        s/^(\s*'syslogd'\).*?;;)/$1\n$bgs/ms; # missing here --------^

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        Update See shmem's note (it's not the escaped paren): It means that you have escaped the closing paren of your capture... as did shmem... and thus have an open paren without a close.

        Please, please: learn to proofread your code, rather than merely asking for that which you then cargo-cult. And please read the relevant documents or texts.

        A reply falls below the community's threshold of quality. You may see it by logging in.
      Thank You, Thank You, Thank You!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (2)
As of 2024-03-19 06:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found