简体   繁体   中英

How can I get rid of the STDERR in Perl

I'm using some system commands in Perl.

In the below case I was getting output as follows:

ls: import-log.*: No such file or directory

ls: error-log.*: No such file or directory

No specified files found for deletion

My code:

sub monthoryear() 
{

  @importlog = `ls -al import-log.*`;

  @errorlog = `ls -al error-log.*`;

}

I don't want to see the following in the output even if there are no files.

ls: import-log.*: No such file or directory &

ls: error-log.*: No such file or directory

While the other answers are correct about the exact technical question you asked, you should also consider not writing what is effectively a shell script in Perl.

You should use Perl native methods of getting file list (eg glob() or File::Find ) instead of calling a backticked ls .

Redirect STDERR to the null device:

use File::Spec;
open STDERR, '>', File::Spec->devnull() or die "could not open STDERR: $!\n";

You can add stderr redirection in your subshell commands:

@importlog = `ls -al import-log.* 2>/dev/null`;
@errorlog = `ls -al error-log.* 2>/dev/null`;

Check out perlfaq8 . If you don't care if it's STDOUT or STDERR , you can get both redirected to STDOUT .

$output = `$cmd 2>&1`;

In your case, you probably just want to get rid of STDERR :

$output = `$cmd 2>/dev/null`;

However, I agree with DVK's answer . Using an external command to get a list of files just seems silly. You should use File::Find . This way you can use Perl's normal error handling in case something fails.

#!/usr/bin/perl
use strict;
use warnings;
use File::Find;

my @importlog;
my @errorlog;
find(sub {
    push @importlog, $File::Find::name if /^import-log\.*/;
    push @errorlog, $File::Find::name if /^error-log\.*/;
}, '.');

print "Import log:\n", join("\n", @importlog), "\n";
print "Error log:\n", join("\n", @errorlog), "\n";

Create a new warn hook, then do something with the message, store it, ignore it etc...

local $SIG{__WARN__} = sub {
  my $message = shift;

  ## do nothing to ignore all together

  ## ignore specific message
  # warn $message unless $message =~ /No such file or directory/;

  ## or do something else
  # die $message ## make fatal
  # open my $fh, '>', 'file.log'; print $fh $message;
};

You can redirect the stderr to /dev/null as:

@importlog = `ls -al import-log.* 2> /dev/null`;

@errorlog = `ls -al error-log.* 2> /dev/null`;

Subshells will inherit the parent's STDERR, so if you want to do it on a global level, you can do this:

open(STDERR,'>/dev/null');
`ls non-existent-file`;
`ls non-existent-file2`;
`ls non-existent-file3`;
`ls non-existent-file4`;
`ls non-existent-file5`;

Often you also want to restore STDERR later. I do this like this:

#!/usr/bin/perl

print STDERR "This will be send to the old (readable) STDERR\n";

my $oldstderr = readlink "/proc/self/fd/2"; #Remember the location of the old STDERR
open(STDERR, ">/dev/null"); #Ignore STDERR now

print STDERR "This will be send to a STDERR that is 'gone'\n";

open(STDERR, ">$oldstderr"); #restores STDERR to the old state

print STDERR "This will be send to the old (readable) STDERR again\n";

OR

You can use the Capture::Tiny module which makes it easier to read and more portable.

#!/usr/bin/perl
use Capture::Tiny qw/capture_stderr/;

print STDERR "This will be send to the old (readable) STDERR\n";
capture_stderr sub {
  print STDERR "This will be send to a STDERR that is 'gone'\n";
};
print STDERR "This will be send to the old (readable) STDERR again\n";

Here's how you can suppress STDERR, capture error messages that occur while turned off, restore STDERR, and report back any captured error messages.

#!/usr/bin/perl
use warnings;
use strict;

print STDERR "STDERR is on.\n";
my ($stderr_fh, $err_msg_ref) = suppress_std_err();
print "STDERR is now off and error messages are being suppressed and saved.\n";
print STDERR "I'm an error message.\n";
restore_std_err($stderr_fh);
print STDERR "STDERR is back on\n";
print "Errors reported while STDERR was off: $$err_msg_ref\n";

#Saves STDERR in filehandle then turns it off.
#Any error messages that occur while STDERR is off are stored for safekeeping.
sub suppress_std_err {
        my $suppressed_std_error_messages;
        open (my $saved_std_err_fh, ">&", STDERR);
        close STDERR;
        open (STDERR, ">", \$suppressed_std_error_messages);
        return ($saved_std_err_fh, \$suppressed_std_error_messages);
}

#Restores STDERR from saved filehandle.
sub restore_std_err {
        my $old_std_err_fh = shift;
        close STDERR;
        open (STDERR, ">&", $old_std_err_fh);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM