aboutsummaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bin')
-rw-r--r--bin/z153
1 files changed, 153 insertions, 0 deletions
diff --git a/bin/z b/bin/z
new file mode 100644
index 0000000..0558436
--- /dev/null
+++ b/bin/z
@@ -0,0 +1,153 @@
+#!/usr/bin/env perl
+
+use v5.34;
+use warnings;
+use feature 'signatures';
+no warnings qw(experimental::signatures);
+use Getopt::Std ();
+use File::Temp ();
+use File::Basename ();
+use List::Util qw(any);
+
+
+sub usage($fh) {
+ print $fh <<~'EOF'
+ Usage:
+ z COMMANDS...
+ z -h
+ EOF
+}
+
+sub help($fh) {
+ print $fh <<~'EOF'
+
+
+ Options:
+ -h, --help show this message
+
+
+ Wrapper that uncompresses file arguments to commands.
+ This enables having commands that operate on plain files to not
+ need to know if they're compressed or not.
+
+ It doesn't depend on the file extension, but on what file(1) says
+ of it.
+
+
+ Examples:
+
+ Replacement for zcat(1p):
+
+ $ z cat a-file.gz
+
+
+ Transparent grep (where my-file.dat is xz compressed):
+
+ $ z grep -E '[a-z]+' my-file.dat
+ EOF
+}
+
+for (@ARGV) {
+ last if $_ eq '--';
+ if ($_ eq '--help') {
+ usage *STDOUT;
+ help *STDOUT;
+ exit;
+ }
+}
+
+my %opts;
+if (!Getopt::Std::getopts('h', \%opts)) {
+ usage *STDERR;
+ exit 2;
+}
+
+if ($opts{h}) {
+ usage *STDOUT;
+ help *STDOUT;
+ exit;
+}
+
+
+# Transform
+# FILENAME: content/type; charset=some\n
+# into
+# content/type
+sub trim($x) {
+ chomp $x;
+ $x =~ s/^.*?: //;
+ $x =~ s/;.*$//;
+ return $x;
+}
+
+my %TYPES = (
+ 'application/gzip' => [qw(gzip -dc)],
+ 'application/x-bzip2' => [qw(bzip2 -dc)],
+ 'application/x-xz' => [qw(xz -dc)],
+ 'application/x-lzma' => [qw(lzma -dc)],
+);
+
+my @tmpfiles;
+sub arg_for($arg) {
+ if (! -e $arg) {
+ return $arg;
+ }
+
+ my $type = trim `file -i $_`;
+ if (any { $type eq $_ } keys %TYPES) {
+ my $template = File::Basename::basename $arg . '.XXXXXX';
+ my ($fh, $tmpname) = File::Temp::tempfile(TEMPLATE => $template);
+ push @tmpfiles, $tmpname;
+ my @command = @{$TYPES{$type}};
+ print $fh `@command $arg`;
+ die $! if $?;
+ close $fh;
+ return $tmpname;
+ }
+
+ return $arg;
+}
+
+sub status_for($n) {
+ if ($n == -1) {
+ return 127;
+ } elsif ($n & 127) {
+ return $n & 127;
+ } else {
+ return $n >> 8;
+ }
+}
+
+my @CMD = map { arg_for $_ } @ARGV;
+exit status_for(system @CMD);
+
+END {
+ unlink @tmpfiles;
+}
+
+
+__END__
+
+=head1 NAME
+
+z - Wrapper that uncompresses file arguments to commands.
+
+=head1 SYNOPSIS
+
+z COMMAND FILE...
+
+=head1 DESCRIPTION
+
+Prefixing a shell command with "zrun" causes any compressed files that are
+arguments of the command to be transparently uncompressed to temp files
+(not pipes) and the uncompressed files fed to the command.
+
+This is a quick way to run a command that does not itself support
+compressed files, without manually uncompressing the files.
+
+The following compression types are supported: gz bz2 Z xz lzma lzo
+
+If zrun is linked to some name beginning with z, like zprog, and the link is
+executed, this is equivalent to executing "zrun prog".
+
+=cut