bufr.pm:bufrread.pl

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
bufr.pm:bufrread.pl [2010-02-24 12:47:18]
pals
bufr.pm:bufrread.pl [2023-02-05 10:14:41] (current)
pals
Line 1: Line 1:
-<code> +<code perl
-#!/usr/bin/perl -w+#!/usr/bin/perl
  
-# (C) Copyright 2010, met.no+# (C) Copyright 2010-2023 MET Norway
 # #
 # This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
Line 19: Line 19:
 # 02110-1301, USA. # 02110-1301, USA.
  
-Usage: bufrread <bufr file(s)> [options] +pod included at end of file
- +
-# Extract Bufr messages from bufr file(s) and decode them. +
-# See subroutine usage_verbose for explanation of the options. +
- +
-# Author: P.Sannes met.no 2010+
  
 use strict; use strict;
 +use warnings;
 use Getopt::Long; use Getopt::Long;
 +use Pod::Usage qw(pod2usage);
 +use Geo::BUFR;
  
-metno module +This is actually default in BUFR.pm, but provided here to make it 
-use BUFR;+# easier for users to change to 'ECCODES' if preferred 
 +use constant DEFAULT_TABLE_FORMAT => 'BUFRDC';
  
-my $DEFAULT_TABLE_PATH = '/usr/local/lib/emos/bufrtables'; +# Will be used if neither --tablepath nor $ENV{BUFR_TABLES} is set 
-my $DEFAULT_CTABLE = 'C0000000000088013001';+use constant DEFAULT_TABLE_PATH_BUFRDC ='/usr/local/lib/bufrtables'; 
 +use constant DEFAULT_TABLE_PATH_ECCODES ='/usr/local/share/eccodes/definitions/bufr/tables'; 
 +# Ought to be your most up-to-date code table(s) 
 +use constant DEFAULT_CTABLE_BUFRDC => 'C0000000000000037000'; 
 +use constant DEFAULT_CTABLE_ECCODES => '0/wmo/37';
  
 # Parse command line options # Parse command line options
Line 39: Line 42:
 GetOptions( GetOptions(
            \%option,            \%option,
-           'all_operators',# Show all operator descriptors when printing section 4 +           'ahl=s',        # Decode BUFR messages with AHL matching <ahl_regexp> only 
-           'bitmap',       # Display bit mapped values on same line+           'all_operators',# Show replication descriptors and all operator descriptors 
 +                           # when printing section 4 
 +           'bitmap',       # Display bit-mapped values on same line
            'codetables',   # Use code and flag tables to resolve values            'codetables',   # Use code and flag tables to resolve values
            'data_only',    # Print section 4 (data section) only            'data_only',    # Print section 4 (data section) only
            'filter=s',     # Decode observations meeting criteria in <filter file> only            'filter=s',     # Decode observations meeting criteria in <filter file> only
            'help',         # Print help information and exit            'help',         # Print help information and exit
 +           'nodata',       # Do not print (nor decode) section 4 (data section)
            'noqc',         # Do not decode quality control            'noqc',         # Do not decode quality control
 +           'on_error_stop', # Stop processing if an error occurs
            'optional_section',  # Display a hex dump of optional section if present            'optional_section',  # Display a hex dump of optional section if present
            'outfile=s',    # Print to file instead of STDOUT            'outfile=s',    # Print to file instead of STDOUT
            'param=s',      # Decode parameters with descriptors in <descriptor file> only            'param=s',      # Decode parameters with descriptors in <descriptor file> only
            'strict_checking=i', # Enable/disable strict checking of BUFR format            'strict_checking=i', # Enable/disable strict checking of BUFR format
 +           'tableformat=s',  # Set BUFR table format
            'tablepath=s',  # Set BUFR table path            'tablepath=s',  # Set BUFR table path
-           'verbose=i',    # Set verbose level to n, 0<=n<=(default 0)+           'verbose=i',    # Set verbose level to n, 0<=n<=(default 0)
            'width=i',      # Set width of values field (default is 15 characters)            'width=i',      # Set width of values field (default is 15 characters)
-       ) or die "Wrong option(s), execute $without arguments for Usage\n";+       ) or pod2usage(-verbose => 0);
  
 # User asked for help # User asked for help
-usage_verbose() if $option{help};+pod2usage(-verbose => 1) if $option{help};
  
 # Make sure there is at least one input file # Make sure there is at least one input file
-usage() unless @ARGV;+pod2usage(-verbose => 0) unless @ARGV;
  
-my $verbose = $option{verbose} $option{verbose} : 0;+# Set verbosity level 
 +Geo::BUFR->set_verbose($option{verbose}) if $option{verbose};
  
-# Set verbosity level for the BUFR module. Must be set also for each +# Set whether section 4 should be decoded for the BUFR module 
-# BUFR object generated +Geo::BUFR->set_nodata() if ($option{nodata});
-BUFR->set_verbose($verbose);+
  
 # Set whether quality information should be decoded for the BUFR module # Set whether quality information should be decoded for the BUFR module
-BUFR->set_noqc() if ($option{noqc});+Geo::BUFR->set_noqc() if ($option{noqc});
  
-BUFR->set_strict_checking($option{strict_checking}) if defined $option{strict_checking};+Geo::BUFR->set_strict_checking($option{strict_checking}) if defined $option{strict_checking};
  
-BUFR->set_show_all_operators($option{all_operators}) if defined $option{all_operators};+Geo::BUFR->set_show_all_operators($option{all_operators}) if defined $option{all_operators}
 + 
 +# Set BUFR table format 
 +my $tableformat = (defined $option{tableformat}) ? uc $option{tableformat} : DEFAULT_TABLE_FORMAT; 
 +Geo::BUFR->set_tableformat($tableformat);
  
 # Set BUFR table path # Set BUFR table path
 if ($option{tablepath}) { if ($option{tablepath}) {
     # Command line option --tablepath overrides all     # Command line option --tablepath overrides all
-    BUFR->set_tablepath($option{tablepath});+    Geo::BUFR->set_tablepath($option{tablepath});
 } elsif ($ENV{BUFR_TABLES}) { } elsif ($ENV{BUFR_TABLES}) {
     # If no --tablepath option, use the BUFR_TABLES environment variable     # If no --tablepath option, use the BUFR_TABLES environment variable
-    BUFR->set_tablepath($ENV{BUFR_TABLES});+    Geo::BUFR->set_tablepath($ENV{BUFR_TABLES});
 } else { } else {
-    # If all else fails, use the libemos bufrtables +    # If all else fails, use the default tablepath in BUFRDC/ECCODES 
-    BUFR->set_tablepath($DEFAULT_TABLE_PATH);+    if ($tableformat eq 'BUFRDC') { 
 +        Geo::BUFR->set_tablepath(DEFAULT_TABLE_PATH_BUFRDC); 
 +    } elsif ($tableformat eq 'ECCODES' { 
 +        Geo::BUFR->set_tablepath(DEFAULT_TABLE_PATH_ECCODES); 
 +    } 
 +
 + 
 +my $ahl_regexp; 
 +if ($option{ahl}) { 
 +    eval { $ahl_regexp = qr/$option{ahl}/ }; 
 +    die "Argument to --ahl is not a valid Perl regular expression: $@" if $@;
 } }
  
Line 89: Line 111:
 my $OUT; my $OUT;
 if ($option{outfile}) { if ($option{outfile}) {
-    open($OUT, '>',$option{outfile})+    open($OUT, '>', $option{outfile})
         or die "Cannot open $option{outfile} for writing: $!";         or die "Cannot open $option{outfile} for writing: $!";
 } else { } else {
Line 101: Line 123:
  
 # Arrays over filter criteria, used if option --filter is set # Arrays over filter criteria, used if option --filter is set
-my @fid;      # Filter descriptors, .e.g. $fid[1] = [ 001001, 001002 ]+my @fid;      # Filter descriptors, e.g. $fid[1] = [ 001001, 001002 ]
 my @fiv;      # Filter values, e.g. $fiv[1] = [ [ 3, 895 ], [ 6 252 ] ] my @fiv;      # Filter values, e.g. $fiv[1] = [ [ 3, 895 ], [ 6 252 ] ]
 my @num_desc; # Number of filter descriptors for each criterion, e.g. $num_desc[1] = 2 my @num_desc; # Number of filter descriptors for each criterion, e.g. $num_desc[1] = 2
Line 119: Line 141:
 # Loop for processing of BUFR input files # Loop for processing of BUFR input files
 foreach my $inputfname ( @ARGV ) { foreach my $inputfname ( @ARGV ) {
-    my $bufr = BUFR->new(); +    my $bufr = Geo::BUFR->new(); 
- +    $bufr->set_filter_cb(\&filter_on_ahl,$ahl_regexp) if $option{ahl};
-    # This sets object verbose level equal to class verbose level +
-    $bufr->set_verbose($verbose)+
- +
-    if ($option{codetables}) { +
-        # Load C table. So far, I don't see the need for user to +
-        # choose another C table than the default table +
-        $bufr->load_Ctable($DEFAULT_CTABLE) +
-            or die "Unable to load table $DEFAULT_CTABLE"; +
-    }+
  
     # Open BUFR file     # Open BUFR file
Line 140: Line 153:
  
  
-# Extract data from BUFR file. +# Extract data from BUFR file. Print AHL for first message in each GTS 
-Print WMO ahl for first message in each WMO bulletin, print +bulletin, print message number for each new message, print subset 
-message number for each new message, print subset number +number for each subset.
-if message contains more than one subset+
 sub decode { sub decode {
-    my $bufr = shift; # BUFR object+    my $bufr = shift;          # BUFR object
  
     my ($message_header, $current_message_number, $current_ahl);     my ($message_header, $current_message_number, $current_ahl);
Line 152: Line 164:
                                # option has been used                                # option has been used
   READLOOP:   READLOOP:
-    while (not $bufr->feof()) {+    while (not $bufr->eof()) {
  
- # Read next observation. If an error is encountered during +        # Read next observation. If an error is encountered during 
- # decoding, skip this observation while printing the error +        # decoding, skip this observation while printing the error 
- # message to STDERR, also displaying ahl of bulletin if found.+        # message to STDERR, also displaying ahl of bulletin if found 
 +        # (but skip error message if the message should be skipped on 
 +        # --ahl anyway).
         my ($data, $descriptors);         my ($data, $descriptors);
- eval {+        eval {
             ($data, $descriptors) = $bufr->next_observation();             ($data, $descriptors) = $bufr->next_observation();
         };         };
         if ($@) {         if ($@) {
 +            $current_ahl = $bufr->get_current_ahl() || '';
 +            next READLOOP if $option{ahl} && $current_ahl !~ $ahl_regexp;
 +
             warn $@;             warn $@;
             # Try to extract message number and ahl of the bulletin             # Try to extract message number and ahl of the bulletin
             # where the error occurred             # where the error occurred
-            eval { +            $current_message_number = $bufr->get_current_message_number(); 
-                $current_message_number = $bufr->get_current_message_number(); +            if (defined $current_message_number{ 
-                $current_ahl = $bufr->get_current_ahl(|| ''; +                my $error_msg = "In message $current_message_number";
-                my $error_msg; +
-                $error_msg = "In message $current_message_number" +
-                    if $current_message_number;+
                 $error_msg .= " contained in bulletin with ahl $current_ahl\n"                 $error_msg .= " contained in bulletin with ahl $current_ahl\n"
                     if $current_ahl;                     if $current_ahl;
                 warn $error_msg if $error_msg;                 warn $error_msg if $error_msg;
-            };+            
 +            exit(1) if $option{on_error_stop};
             next READLOOP;             next READLOOP;
         }         }
  
-        if ($option{param}) { +        next if $option{ahl} && $bufr->is_filtered(); 
-            # Reduce data and descritors to those requested only + 
-            ($data, $descriptors+        if ($option{codetables} && !$option{nodata}) { 
-                = param($data, $descriptors@requested_desc);+            # Load C table, trying first to use same table version as 
 +            # the B and D tables loaded in next_observation, or if 
 +            # this C table file does not exist, loads DEFAULT_CTABLE 
 +            # instead. 
 +            my $table_version = $bufr->get_table_version(); 
 +            my $tableformat = Geo::BUFR->get_tableformat(); 
 +            if ($tableformat eq 'BUFRDC'{ 
 +                $bufr->load_Ctable("C$table_version"DEFAULT_CTABLE_BUFRDC); 
 +            } elsif ($tableformat eq 'ECCODES'
 +                $bufr->load_Ctable("$table_version"DEFAULT_CTABLE_ECCODES); 
 +            }
         }         }
  
         my $current_subset_number = $bufr->get_current_subset_number();         my $current_subset_number = $bufr->get_current_subset_number();
-        my $nsubsets = $bufr->get_number_of_subsets();+        # If next_observation() did find a BUFR message, subset number 
 +        # should have been set to at least 1 (even in a 0 subset message) 
 +        last READLOOP if $current_subset_number == 0;
  
-        if ($current_subset_number == 1) {+        if ($current_subset_number == 1 || $option{nodata}) {
             $current_message_number = $bufr->get_current_message_number();             $current_message_number = $bufr->get_current_message_number();
             $current_ahl = $bufr->get_current_ahl() || '';             $current_ahl = $bufr->get_current_ahl() || '';
Line 195: Line 222:
  
             $section013_dumped = 0;             $section013_dumped = 0;
-            next READLOOP if $option{filter} +            next READLOOP if ($option{filter} 
-                and filter_observation($bufr, $data, $descriptors);+                && filter_observation($bufr, $data, $descriptors));
  
             print $OUT $message_header;             print $OUT $message_header;
Line 208: Line 235:
                 $section013_dumped = 1;                 $section013_dumped = 1;
             }             }
 +            next READLOOP if $option{nodata};
         } else { # subset number > 1         } else { # subset number > 1
-            next READLOOP if $option{filter} +            next READLOOP if ($option{filter} 
-                and filter_observation($bufr, $data, $descriptors);+                && filter_observation($bufr, $data, $descriptors));
  
             # If subset 1 was filtered away, section 0-3 might not             # If subset 1 was filtered away, section 0-3 might not
Line 225: Line 253:
         }         }
  
-        if ($nsubsets > 1) { +        if ($option{param}) { 
-            printf $OUT "\nSubset %d\n", $current_subset_number;+            # Reduce data and descriptors to those requested only 
 +            ($data, $descriptors) 
 +                = param($data, $descriptors, @requested_desc);
         }         }
-        if ($option{bitmap}) { + 
-            print $OUT $bufr->dumpsection4_with_bitmaps($data, $descriptors, $width);+        printf $OUT "\nSubset %d\n", $current_subset_number; 
 + 
 +        # If an error is encountered during dumping of section 4, skip 
 +        # this subset while printing the error message to STDERR, also 
 +        # displaying ahl of bulletin if found. 
 +        my $dump; 
 +        eval { 
 +            $dump = ( $option{bitmap} ) 
 +                ? $bufr->dumpsection4_with_bitmaps($data, $descriptors
 +                                                   $current_subset_number, $width) 
 +                : $bufr->dumpsection4($data, $descriptors, $width); 
 +        }; 
 +        if ($@) { 
 +            warn $@; 
 +            my $error_msg = "In message $current_message_number" 
 +                . " and subset $current_subset_number"; 
 +            $error_msg .= " contained in bulletin with ahl $current_ahl\n" 
 +                if $current_ahl; 
 +            warn $error_msg; 
 +            exit(1) if $option{on_error_stop}; 
 +            next READLOOP;
         } else {         } else {
-            print $OUT $bufr->dumpsection4($data, $descriptors, $width);+            print $OUT $dump;
         }         }
     }     }
Line 246: Line 296:
         push @requested_desc, $1;         push @requested_desc, $1;
     }     }
 +    close $fh or die "Cannot close $descriptor_file: $!";
     return @requested_desc;     return @requested_desc;
 } }
  
 # Reduce the data to those corresponding to the requested descriptors # Reduce the data to those corresponding to the requested descriptors
-# only+# only.
 sub param { sub param {
     my ($data, $descriptors, @requested_desc) = @_;     my ($data, $descriptors, @requested_desc) = @_;
Line 266: Line 317:
 } }
  
-sub usage { 
-    print <<"EOF"; 
-Usage: $0 <bufr file(s)> 
-        [--codetables] 
-        [--data_only] 
-        [--param <descriptor file>] 
-        [--filter <filter file>] 
-        [--bitmap] 
-        [--noqc] 
-        [--outfile <filename>] 
-        [--optional_section] 
-        [--width n] 
-        [--strict_checking n] 
-        [--all_operators] 
-        [--tablepath <path to BUFR tables>] 
-        [--verbose n] 
-        [--help] 
-Try 'bufrread.pl --help' for more information. 
-EOF 
-    exit 0; 
-} 
- 
- 
-sub usage_verbose { 
-    print <<"EOF"; 
- 
-Usage: $0 <bufr file(s)> [options] 
- 
-Will print section 0-4 in BUFR messages in <bufr file(s)>. 
-Options (may be abbreviated, e.g. --h or -h for --help) are: 
- 
-        --codetables    Use code and flag tables to resolve values where unit 
-                        is [CODE TABLE] or [FLAG TABLE] 
-        --data_only     Print section 4 (data section) only 
-        --param <descriptor file> 
-                        Decode parameters with descriptors in <descriptor file> only 
-        --filter <filter file> 
-                        Decode observations meeting criteria in <filter file> only 
-        --bitmap        Display bit mapped values on same line 
-        --noqc          Do not decode quality control 
-                        (or any descriptors following 222000) 
-        --outfile <filename> 
-                        Will print to <filename> instead of STDOUT 
-        --optional_section 
-                        Display a hex dump of optional section if present 
-        --width n       Set width of field used for data values to n characters 
-                        (default is 15) 
-        --strict_checking n n=0 (default) Disable strict checking of BUFR format 
-                            n=1 Issue warning if (recoverable) error in 
-                                BUFR format 
-                            n=2 Croak if (recoverable) error in BUFR format. 
-                                Nothing more in this message will be decoded. 
-        --all_operators Show all operator descriptors when printing section 4 
-        --tablepath <path to BUFR tables> 
-                        Set path to BUFR tables (overrides ENV{BUFR_TABLES}) 
-        --verbose n     Set verbose level to n, 0<=n<=3 (default 0) 
-        --help          Print this Usage 
- 
-You should probably set 
-        export BUFR_TABLES=$DEFAULT_TABLE_PATH 
-or use the --tablepath option. 
- 
-Each line in <descriptor file> should start with a BUFR descriptor (6 digits). 
-Rest of line will be ignored. bufrread will extract values for these descriptors 
-only. If used together with --filter, <descriptor file> must contain all descriptors 
-in <filter file>. 
- 
-Using --filter will decode only those observations that meet one of the criteria in 
-<filter file> (and all of those criteria marked D!). Comments (starting with #) are 
-ignored. An example of a filter file is 
- 
-# All stations in WMO block 01 
-D: 001001 
-1 
-D: 001001 001002 
-3 895 
-6 252 
-D: 001011 
-LF5U       # Ekofisk 
-D!: 004004 
-6 
-7 
- 
-which decodes all observations with block number 01, two other specific wmo stations 
-and one specific ship, all of which having hour (004004) equal to 6 or 7. 
-If there is no value line after a descriptor line, it is enough that the observation 
-contains the descriptor(s), whatever the values are. So to extract all ship messages 
-from a BUFR synop file, the filter file should contain this single line only: 
- 
-D: 001011 
- 
-If an error occurs during decoding (typically because the required BUFR table is 
-missing or message is corrupt) the message is skipped, and the number of errors 
-is reported at end of output. 
- 
-EOF 
-    exit 0; 
-} 
  
 ################################################################################### ###################################################################################
Line 369: Line 322:
 # Filter routines # Filter routines
  
-# Read in content of $filter_file into variables @fid, @fiv,+sub filter_on_ahl { 
 +    my $obj = shift; 
 +    my $ahl_regexp = shift; 
 +    my $ahl = $obj->get_current_ahl() || ''; 
 +    return $ahl =~ $ahl_regexp ? 0 : 1; 
 +
 + 
 +# Read in contents of $filter_file into variables @fid, @fiv,
 # @num_desc, @num_val and $num_criteria, which are defined above. # @num_desc, @num_val and $num_criteria, which are defined above.
 +# Note that index 0 of the arrays is not used.
 sub read_filter_file { sub read_filter_file {
     my $filter_file = shift;     my $filter_file = shift;
Line 377: Line 338:
         or die "Cannot open $filter_file: $!";         or die "Cannot open $filter_file: $!";
     while (<$fh>) {     while (<$fh>) {
-        # Remove comments+        # Remove comments and skip blank lines
         s/#.*//;         s/#.*//;
-        next if /^$/;+        next if /^\s*$/;
  
         if (s/^\s*D(!)?://) {         if (s/^\s*D(!)?://) {
             my @desc = split;             my @desc = split;
 +            # Check that all descriptors are numbers
 +            foreach my $desc (@desc) {
 +                die "'$desc' cannot be a descriptor in line $. in filter file '$filter_file'"
 +                    if $desc !~/^\d+$/;
 +            }
 +            # Save the criterium
             $num_desc[++$num_criteria] = @desc;             $num_desc[++$num_criteria] = @desc;
             $num_val[$num_criteria] = 0;             $num_val[$num_criteria] = 0;
Line 390: Line 357:
         } else {         } else {
             my @values = split;             my @values = split;
 +            # Check that value line contains correct number of values
 +            die "Number of values doesn't match number of descriptors"
 +                . " for line $. in filter file '$filter_file'"
 +                if scalar @values != scalar @{$fid[$num_criteria]};
 +            # Remove leading 0's in numerical values (to prepare for string comparison)
 +            for $_ (@values) { s/^0+(\d+)$/$1/ };
             $fiv[$num_criteria]->[++$num_val[$num_criteria]] = \@values;             $fiv[$num_criteria]->[++$num_val[$num_criteria]] = \@values;
         }         }
     }     }
 +    close $fh or die "Cannot close $filter_file: $!";
     return;     return;
 } }
Line 398: Line 372:
 # Return true (observations should be filtered) if the observation # Return true (observations should be filtered) if the observation
 # does not meet all of the D! criteria (if exists) and does not meet # does not meet all of the D! criteria (if exists) and does not meet
-# any one of the other criteria (if exists) in filter file+# any one of the other criteria (if exists) in filter file.
 sub filter_observation { sub filter_observation {
     my $bufr = shift;     my $bufr = shift;
     die "Error in filter_observation: argument not a BUFR object"     die "Error in filter_observation: argument not a BUFR object"
-        unless ref($bufr) eq 'BUFR';+        unless ref($bufr) eq 'Geo::BUFR';
     my ($data, $descriptors) = @_;     my ($data, $descriptors) = @_;
  
-    my $num_ordinary_criteria = @fid - $num_required_criteria;+    my $num_ordinary_criteria = $#fid - $num_required_criteria;
     my $num_success_req_criteria = 0; # Number of required criteria successfully fulfilled     my $num_success_req_criteria = 0; # Number of required criteria successfully fulfilled
     my $num_success_ord_criteria = 0; # Number of ordinary criteria successfully fulfilled     my $num_success_ord_criteria = 0; # Number of ordinary criteria successfully fulfilled
Line 450: Line 424:
                     for (my $j = 0; $j < @{$descriptors}; $j++) {                     for (my $j = 0; $j < @{$descriptors}; $j++) {
                         if ($descriptors->[$j] == $filter_desc) {                         if ($descriptors->[$j] == $filter_desc) {
 +                            next DESC if !defined $data->[$j];
                             (my $val = $data->[$j]) =~ s/^\s*(.*?)\s*$/$1/;                             (my $val = $data->[$j]) =~ s/^\s*(.*?)\s*$/$1/;
                             if ($val eq $fiv[$filter_criterion]->[$line]->[$idesc]) {                             if ($val eq $fiv[$filter_criterion]->[$line]->[$idesc]) {
Line 462: Line 437:
                                                  or $num_success_ord_criteria > 0)) {                                                  or $num_success_ord_criteria > 0)) {
                                             return 0; # Don't filter this observation                                             return 0; # Don't filter this observation
 +                                        } else {
 +                                            next DESC;
                                         }                                         }
                                     } else {                                     } else {
Line 488: Line 465:
     return 1;     return 1;
 } }
 +
 +=pod
 +
 +=encoding utf8
 +
 +=head1 SYNOPSIS
 +
 +  bufrread.pl <bufr file(s)>
 +      [--ahl <ahl_regexp>]
 +      [--all_operators]
 +      [--bitmap]
 +      [--codetables]
 +      [--data_only]
 +      [--filter <filter file>]
 +      [--help]
 +      [--nodata]
 +      [--noqc]
 +      [--on_error_stop]
 +      [--optional_section]
 +      [--outfile <filename>]
 +      [--param <descriptor file>]
 +      [--strict_checking n]
 +      [--tableformat <BUFRDC|ECCODES>]
 +      [--tablepath <path to BUFR tables>]
 +      [--verbose n]
 +      [--width n]
 +
 +=head1 DESCRIPTION
 +
 +Extract BUFR messages from BUFR file(s) and print the decoded content
 +to screen, including AHL (Abbreviated Header Line) if present.
 +
 +Execute without arguments for Usage, with option C<--help> for some
 +additional info. See also L<https://wiki.met.no/bufr.pm/start> for
 +examples of use.
 +
 +
 +=head1 OPTIONS
 +
 +   --ahl <ahl_regexp>
 +                   Decode BUFR messages with AHL matching <ahl_regexp> only
 +   --all_operators Show replication descriptors and all operator descriptors
 +                   when printing section 4
 +   --bitmap        Display bit-mapped values on same line
 +   --codetables    Use code and flag tables to resolve values when unit
 +                   is [CODE TABLE] or [FLAG TABLE]
 +   --data_only     Print section 4 (data section) only
 +   --filter <filter file>
 +                   Decode observations meeting criteria in <filter file> only
 +   --help          Display Usage and explain the options used. For even
 +                   more info you might prefer to consult perldoc bufrread.pl
 +   --nodata        Do not print (nor decode) section 4 (data section)
 +   --noqc          Do not decode quality control
 +                   (or any descriptors following 222000)
 +   --on_error_stop Stop processing as soon as an error occurs during decoding
 +   --outfile <filename>
 +                   Will print to <filename> instead of STDOUT
 +   --optional_section
 +                   Display a hex dump of optional section if present
 +   --param <descriptor file>
 +                   Display parameters with descriptors in <descriptor file> only
 +   --strict_checking n n=0 (default) Disable strict checking of BUFR format
 +                       n=1 Issue warning if (recoverable) error in
 +                           BUFR format
 +                       n=2 Croak if (recoverable) error in BUFR format.
 +                           Nothing more in this message/subset will be decoded.
 +   --tableformat   Currently supported are BUFRDC and ECCODES (default is BUFRDC)
 +   --tablepath <path to BUFR tables>
 +                   Set path to BUFR tables (overrides ENV{BUFR_TABLES})
 +   --verbose n     Set verbose level to n, 0<=n<=6 (default 0). n=1 will
 +                   show the tables loaded.
 +   --width n       Set width of field used for data values to n characters
 +                   (default is 15)
 +
 +Options may be abbreviated, e.g. C<--h> or C<-h> for C<--help>.
 +
 +To avoid having to use the C<--tablepath> option, you are adviced to
 +set the environment variable BUFR_TABLES to the directory where your
 +BUFR tables are located (unless the default path provided by
 +bufrread.pl works for you). For tableformat ECCODES, se
 +L<http://search.cpan.org/dist/Geo-BUFR/lib/Geo/BUFR.pm#BUFR-TABLE-FILES>
 +for more info on how to set C<--tablepath> (or BUFR_TABLES).
 +
 +For option C<--ahl> the <ahl_regexp> should be a Perl regular
 +expression. E.g. C<--ahl "ISS... ENMI"> will decode only BUFR SHIP
 +(ISS) from CCCC=ENMI. This is the only case where a little knowledge
 +of Perl might possibly be required when using the utility programs
 +included in Geo::BUFR.
 +
 +For option C<--param> each line in <descriptor file> should start with
 +a BUFR descriptor (6 digits).  Rest of line will be ignored.
 +bufrread.pl will display values for these descriptors only.
 +
 +Using C<--filter> will decode only those observations that meet one of
 +the criteria in <filter file> marked D: and all of those criteria
 +marked D!:. Comments (starting with #) are ignored. An example of a
 +filter file is
 +
 +  D: 001001
 +  1
 +  D: 001001 001002
 +  3 895
 +  6 252
 +  D: 001011
 +  LF5U       # Ekofisk
 +  D!: 004004
 +  6
 +  7
 +
 +which decodes all observations with block number 01, two other
 +specific WMO stations and one specific ship, all of which having hour
 +(004004) equal to 6 or 7. If there is no value line after a
 +descriptor line, it is enough that the observation contains the
 +descriptor(s), whatever the values are. So to extract all ship
 +messages from a BUFR file, the filter file should contain this single
 +line only:
 +
 +  D: 001011
 +
 +If an error occurs during decoding (typically because the required
 +BUFR table is missing or message is corrupt), the BUFR message is
 +skipped with an error message printed to STDERR, and processing then
 +continues with the next BUFR message. You can change this default
 +behaviour, however, by setting C<--on_error_stop>.
 +
 +=head1 CAVEAT
 +
 +Option C<--bitmap> may not work properly for complicated BUFR messages.
 +Namely, when the first bit-map is encountered, no more data values (or
 +their descriptors) will be displayed unless they refer to the
 +preceding data values by a bit-map. And output is not to be trusted
 +if a bit-map refers to another bit-map or the bit-mapped values are
 +combined with 204YYY (add associated field operator).
 +
 +=head1 AUTHOR
 +
 +Pål Sannes E<lt>pal.sannes@met.noE<gt>
 +
 +=head1 COPYRIGHT
 +
 +Copyright (C) 2010-2023 MET Norway
 +
 +=cut
 </code> </code>
  • bufr.pm/bufrread.pl.1267015638.txt.gz
  • Last modified: 2022-05-31 09:23:11
  • (external edit)