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

Hi, Im trying to output some lines of input if they contain certain regexp, but am having trouble with the output file. I am using the code below:

if (-z BADSYMS ) { (`rm BADSYMS.out`); } else { print ("Bad symbols contained in BADSYMS.out\n"); }

I want to test to see if the file is empty and if so remove it. Otherwise I want to print the name of it.

I am currently opening the file at the beginning of the script, as opposed to opening it only if the pattern is matched.

Am I using the -z incorrectly? I have also tried the -s by assigning it to a scalar and seeing if ==0 but this hasn't worked correctly either.

Any thoughts?

Thanks, Martin

Replies are listed 'Best First'.
Re: -z file test operator
by tomhukins (Curate) on Aug 30, 2001 at 16:49 UTC

    You are testing whether a file called BADSYMS is zero sized (if (-z BADSYMS)), but trying to remove a file called BADSYMS.out. You're not quoting the filename in this line either.

    Also, there's no need to fork off a shell for rm. Use Perl's builtin unlink instead.

    Try this:

    use strict; use warnings; if (-z 'BADSYMS.out') { unlink 'BADSYMS.out' or die 'Could not delete BADSYMS.out'; } else { print "Bad symbols contained in BADSYMS.out\n"; }

      2 important notes on the error check.

      First of all you should make sure that your die message contains the output of $!, the operating system error will often greatly simplify debugging.

      Secondly I suggest putting the name of the file into a variable and using that variable in both the open and the die. The reason is that otherwise it is far too easy for someone to come along and change what file is being opened but not edit the error check. That can be a real pain to debug. When you can, you want to reduce the need to synchronize code...

      I opened the file using

      unless (open (BADSYMS, ">BADSYMS.out")) { die ("Can't open output file BADSYMS.out\n");

      So i presumed that when using the -z I could test against the filehandle, do I need to use the quotes?

      Now I get this error message

      Can't exec "BADSYMS.out": Permission denied

      This is the code I now have in:

      if (-z `BADSYMS.out` ) { # unlink `BADSYMS.out` or die `Cant delete BADSYMS.out`; print "hi"; } else { print "Bad symbols contained in BADSYMS.out\n"; }

      I have commented out the unlink, as it was going straight to it, regardless of whether the file was 0 or not. When it prints out the "hi" regardless I know the -z isn't working

      any ideas?

        Don't use backticks like `BADSYMS.out` - instead use normal single or double quotes:

        if (-z "BADSYMS.out") { # do something }
        The backticks try to execute the file which is not what you want.

        -- Hofmator

Re: -z file test operator
by Zaxo (Archbishop) on Aug 30, 2001 at 17:30 UTC

    It looks like you apply the test to an open filehandle and then try unlinking with the same handle. Unlinking should be done on the filename. The -z test should be done after the filehandle is closed to ensure all data is written. Unlinking an open file is Not Good. This is better:

    # assumes the file is named in a variable $badsyms. # $badsyms would best be an absolute path. # # close(BADSYMS); before this, otherwise writes may not be # flushed before the test. # That would give a false positive if ( -z $badsyms ) { unlink $badsyms or die "Cannot unlink $badsyms: $!"; } else { print "Bad symbols contained in $badsyms\n"; }
    It would be helpful to see what kind of loop this is in and how the filenames are obtained. I may have misunderstood what you are doing.

    .

    Update: Added death on error.

    Update2: Re AM's followup The BADSYMS filehandle is already closed. Replace with "BADSYMS.out" in the -z test.

    After Compline,
    Zaxo

      Hi, now I am using:
      close (BADSYMS); if (-z BADSYMS ) { unlink "BADSYMS.out" or die ("Cant delete BADSYMS.out"); print "hi"; } else { print "Bad symbols contained in BADSYMS.out\n"; }

      What happens now is when the file is zero or not zero, the if part is skipped, and it goes straight to the else. When the file is non-zero a message is returned:

      Stat on unopened file <BADSYMS> at test.pl line 317

      The filenames are assigned at the start of the script

      unless (open (BADSYMS, ">BADSYMS.out")) { die ("Can't open output file BADSYMS.out\n"); }

      This isn't in a loop as such, the script runs and the file maybe written to, if it isn't and therefore is empty, I want to delete it. If it is written to I want the print statement to output the name.

      Thanx, Martin

        Your problems are 1) you close the file handle then try to test it. 2) You can't unlink an file that has an open filehandle on many systems. This should be self explanatory code. $file is the FILE NAME. We open this file onto the FILE HANDLE called BAD. We can then read from the file through the filehandle.

        $file = "bad.out"; open BAD, $file or die "Oops can't open $file Perl says $!\n" # do stuff to BAD close BAD; if ( -s $file ) { # file has size } else { # file has zero size unlink $file or die "Can't unlink $file: $!\n"; }

        PS Get a login! cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: -z file test operator
by tachyon (Chancellor) on Aug 30, 2001 at 17:24 UTC

    You can use the filetest operators on either a filename or a FILEHANDLE. Here is a demo, save it as whatever. It opens itself, tests for file size against its name and FH (both the same) and then unlinks itself:

    open SELF, $0 or die "Can't open myself $!\n"; print "My name is $0\n"; print "I am ", -s SELF, " bytes\n"; print "That's ", -s $0, " bytes\n"; close SELF; unlink $0 and die "Deleted myself, I'm outta here!\n";

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: -z file test operator
by stefan k (Curate) on Aug 30, 2001 at 16:55 UTC
    As far as I can see you're not testing the real filename: put it into quotes and use the full name:
    if (-z "BADSYMS.OUT") { system("rm BADSYMS.OUT"); } else { print "Bad symbols..."; }

    Update: Too slow once again, and tomhukins used strict and unlink plus error checking which I should have used, too. Shame on me :)

    Regards... Stefan
    you begin bashing the string with a +42 regexp of confusion