Last active
May 25, 2022 17:21
-
-
Save philpennock/7049516 to your computer and use it in GitHub Desktop.
Used to iterate over PEM-encoded items in a file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
# | |
# For a file containing PEM objects or PGP objects or whatever, emit the file | |
# filtering the objects through a command-line which takes the object on stdin. | |
# | |
# foreach-beginend bundle.crt openssl x509 -noout -text | |
# The filename may be specified as '-' to act as a filter reading from stdin. | |
# | |
use strict; | |
use warnings; | |
BEGIN { pop @INC if $INC[-1] eq '.' }; | |
use File::Basename qw(); | |
use Getopt::Long; | |
use IO::File; | |
my $VERBOSE = 0; | |
my $PRINT_ONLY_PEMBLOCK = 0; | |
my $NEED_USAGE = undef; | |
my $SEPARATOR_TEXT = undef; | |
Getopt::Long::Configure qw/no_auto_abbrev no_getopt_compat require_order bundling/; | |
GetOptions( | |
'verbose|v!' => \$VERBOSE, | |
'help|h!' => \$NEED_USAGE, | |
'pemonly!' => \$PRINT_ONLY_PEMBLOCK, | |
'separator|s=s' => \$SEPARATOR_TEXT, | |
) or die "Error in command-line flags\n"; | |
if (scalar @ARGV < 2 and not defined $NEED_USAGE) { | |
$NEED_USAGE = -1; | |
} | |
if (defined $NEED_USAGE and $NEED_USAGE) { | |
select STDERR if $NEED_USAGE < 0; | |
print "Usage: foreach-beginend [<flags>] <file> <command> <command-args ...>\n"; | |
print " args may be %{TEMPLATE} based\n"; | |
print " templates: COUNTER FILENAME BASENAME\n"; | |
print " --pemonly do not print lines from outside PEM blocks\n"; | |
print " --separator TXT show TXT between each command (+newline if not present)\n"; | |
print " -s TXT same as --separator\n"; | |
exit (($NEED_USAGE < 0) ? -$NEED_USAGE : 0); | |
} | |
my $fn = shift @ARGV; | |
my $fh; | |
if ($fn eq '-') { | |
$fh = \*STDIN; | |
} else { | |
$fh = new IO::File $fn, '<' or die "read-open($fn) failed: $!\n"; | |
} | |
sub expand_one_template { | |
my ($t, $opts) = @_; | |
my %direct_vars = ( | |
counter => -1, | |
filename => 'anonymous', | |
basename => 'anonymous', | |
); | |
foreach my $k (keys %direct_vars) { | |
next unless $t eq uc $k; | |
return $opts->{$k} if exists $opts->{$k}; | |
return $direct_vars{$k}; | |
} | |
return 'unknown'; | |
} | |
sub argv_expand_templates { | |
local %_=@_; | |
die "no argv" unless exists $_{'argv'}; | |
my @args; | |
foreach my $a (@{$_{'argv'}}) { | |
(my $b = $a) =~ s/%\{([^}]+)\}/expand_one_template($1, \%_)/eg; | |
push @args, $b; | |
} | |
return @args; | |
} | |
my $fn_base = File::Basename::basename $fn; | |
my $in_block = 0; | |
my @block; | |
my $counter = 0; | |
my $shown = 0; | |
while (<$fh>) { | |
if ($in_block) { | |
push @block, $_; | |
next unless /^-----END/; | |
if ($shown) { | |
# There's intervening lines from the input, shown unless pemonly. | |
# There's also optional separator text to emit, which is strictly | |
# a separator, not a prefix or suffix. | |
if (defined $SEPARATOR_TEXT) { | |
print $SEPARATOR_TEXT; | |
print "\n" unless $SEPARATOR_TEXT =~ /\n\z/; | |
} | |
} | |
local $| = 1; | |
my @args = argv_expand_templates( | |
argv => \@ARGV, | |
counter => $counter, | |
filename => $fn, | |
basename => $fn_base, | |
# If changing these, don't forget to update the usage text | |
); | |
open(CMD, '|-', @args) or do { | |
print STDERR "failed to run [@args]: $!\n"; | |
@block = (); | |
$in_block = 0; | |
next; | |
}; | |
print CMD @block; | |
close(CMD); | |
@block = (); | |
if ($? != 0) { | |
my ($ex, $sig, $core) = ($? >> 8, $? & 127, $? & 128); | |
my $emsg = "$args[0] died"; | |
$emsg .= ", exiting $ex" if $ex; | |
$emsg .= ", signal $sig" if $sig; | |
$emsg .= ' (core dumped)' if $core; | |
print STDERR "$emsg\n"; | |
} | |
$in_block = 0; | |
$shown++; | |
next; | |
} | |
if (/^-----BEGIN/) { | |
@block = ($_); | |
$in_block = 1; | |
$counter++; | |
print "\n***** Item $counter at line $. *****\n" if $VERBOSE; | |
next; | |
} | |
print $_ unless $PRINT_ONLY_PEMBLOCK; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment