#!/usr/bin/env perl use Getopt::Long; $Getopt::Long::autoabbrev = 1; $Getopt::Long::ignorecase = 0; use File::Basename; use strict; # Defaults + Variables my $dmaxchannel = 64 my $maxchannel = -1; my $dbytes = 3; my $bytes = -1; my $dreadinc = 500; my $readinc = -1; my $channel = -1; my $infile = ""; my $outfile = ""; my $force = 0; my $quiet = 0; my $use1of = 0; # Usage my $usage =<< "END"; Usage: $0 [--outfile F] [--channels C] [--bytes B] [--readinc R] [--force] [--quiet] channelnumber inputfile [inputfile inputfile ...] channelnumber channel to extract inputfile file to open (raw data) --outfile F file to write the extracted channel to (default is "channelnumber-inputfile"). Only one file can be specified, all data from input files will be concatenated to this file. --channels C number of channels in the input file (default: $dmaxchannel) --bytes B number of bytes per channel in the input file (default: $dbytes) --readinc R Number of chunks of data to process at a time (for speedup vs memory use) (default: $dreadinc) --force Forces the use of input file if its size does not match the 'channels*bytes' requirements --quiet Run in quiet mode END # Option processing + use of default values GetOptions ( 'outfile=s' => \$outfile, 'channels=i' => \$maxchannel, 'bytes=i' => \$bytes, 'readinc=i' => \$readinc, 'force' => sub {$force = 1;}, 'quiet' => sub {$quiet = 1;} ) || usage(); $maxchannel = $dmaxchannel if ($maxchannel == -1); $bytes = $dbytes if ($bytes == -1); $readinc = $dreadinc if ($readinc == -1); my $verb = ($quiet == 1) ? 0 : 1; $use1of = ($outfile ne "") ? 1 : 0; $| = 1 if ($verb); # Channel number $channel = shift @ARGV; die "Error: Channel ($channel) must be between 1 and $maxchannel\n\n$usage" if (($channel < 1) || ($channel > $maxchannel)); #################### # Opening/Checking Input file my @tinfiles = @ARGV; my @infiles; my $tfs = 0; my %fs; print "\nChecking input file(s)..." if ($verb); foreach $infile (@tinfiles) { die "Error: Invalid file name ($infile)\n" if ($infile eq ""); $infile =~ s{^~([^/]*)}{$1?(getpwnam($1))[7]:($ENV{HOME} || $ENV{LOGDIR})}ex; push @infiles, $infile; if (exists $fs{$infile}) { print "Warning: file ($infile) seems to be listed more than once\n"; next; } die "Error: Input file ($infile) does not exist, aborting !\n" if (! -e $infile); $fs{$infile} = (stat($infile))[7]; $tfs += $fs{$infile}; die "Error: Input file size (" . $fs{$infile} . ") is not a multiple of $maxchannel channels by $bytes bytes (maybe not a \"real\" raw file); use \'--force\' to process this file\n" if ((! $force) && ($fs{$infile} % ($maxchannel * $bytes))); open INFILE, "<$infile" or die "Error: Could not open input file ($infile): $!\n\n$usage"; close INFILE; } print " done\n" if ($verb); #################### # Processing each input files my $totalread; my $percent; my ($tottofs, $totwofs); while ($infile = shift @infiles) { # "foreach" does not seem to set $infile ### Creating outputfile # Multiple output files if ($use1of == 0) { if ($outfile eq "") { $outfile = $infile; $outfile =~ /^(.*?)([^\/]+)$/; my $infile_dir = $1; my $infile_file = $2 ; $outfile = $infile_dir . sprintf("%02d", $channel) . "-$infile_file"; } } # Multiple and single output file if (($use1of - 1) <= 0) { $outfile =~ s{^~([^/]*)}{$1?(getpwnam($1))[7]:($ENV{HOME} || $ENV{LOGDIR})}ex; my $as = checkspaceleft($outfile); my $sr = (($use1of == 1) ? $tfs : $fs{$infile}) / $maxchannel; my $ksr = $sr / 1024; # kb value (for 'df -k') die "Error: Not enough space left on device for writting output file ($outfile), estimated size of $ksr KB is more than available ($as KB), aborting\n" if ($as < $ksr); open OUTFILE, ">$outfile" or die "Error: Could not open output file ($outfile): $!\n\n$usage"; binmode OUTFILE; } # One output file ... stay with only one $use1of++ if ($use1of == 1); ### Opening inputfile open INFILE, "<$infile" or die "Error: Could not open input file ($infile): $!\n\n$usage"; binmode INFILE; if ($verb) { print "\n"; print << "END"; Will extract: - Channel $channel (out of $maxchannel) with $bytes byte(s) per channel - Input file : $infile - Output file: $outfile - will read/write a group of $readinc such elements at a time (for speedup) END print "\n"; } my $toread = $readinc*$maxchannel*$bytes; my $toskip_pre = $bytes*($channel - 1); my $toskip_post = ($maxchannel - $channel)*$bytes; my $running = 1; my $read = 0; my $outsize = 0; my $buffer; $percent = -1; # Set the variable even if we do not use it $totalread = 0; while ($running) { $read = read(INFILE, $buffer, $toread); $totalread += $read; $running = 0 if ($read < $toread); my $outbuffer = ""; for (my $i = 0; $i < $read; $i += $maxchannel*$bytes) { my $done = ($buffer =~ s/^.{$toskip_pre}(.{$bytes}).{$toskip_post}//s); if ($done) { $outbuffer .= $1; $outsize += $bytes; } } print OUTFILE $outbuffer; pprint(); } if (! $quiet) { print "\rProgress ... done \n\n"; print "Read from input file : ", $totalread, " bytes\n"; print "Supposed output file size: ", $totalread / $maxchannel, " bytes\n"; print "Written to output file : ", $outsize, " bytes\n"; } if ($use1of == 2) { $tottofs += $totalread / $maxchannel; $totwofs += $outsize; } close INFILE; close OUTFILE if ($use1of == 0); } if ($use1of == 2) { close OUTFILE; if ($verb) { print "\n"; print "Total supposed output file size : ", $tottofs, " bytes\n"; print "Total written output file size : ", $totwofs, " bytes\n"; print "Real output file size : ", (stat($outfile))[7], " bytes\n"; } } sub checkspaceleft { my $file = shift @ARGV; my $return = 10000; my $match = ""; my $base = dirname($file); $base = $ENV{PWD} if ($base eq "."); my @tmp = 'df -k'; chomp(@tmp); shift(@tmp); foreach my $line (@tmp) { my ($dev, $blocks, $used, $avail, $cap, $mount) = split(/\s+/, $line); next if ($base !~ /^$mount/); if (length($match) < length($mount)) { $match = $mount; $return = $blocks; } } return $return; } sub pprint { return if ($quiet); my $t = int (100 * $totalread / $fs{$infile}); if ($t > $percent) { printf("\rProgress: %03d %%", $t); $percent = $t; } }