Skip to content

Instantly share code, notes, and snippets.

@markasoftware
Created May 15, 2019 04:36
Show Gist options
  • Save markasoftware/cfc76f02c880ed43f622cb7be3f0b3c0 to your computer and use it in GitHub Desktop.
Save markasoftware/cfc76f02c880ed43f622cb7be3f0b3c0 to your computer and use it in GitHub Desktop.
SeqSwap
#!/usr/bin/env perl
# Copyright (c) Mark Polyakov 2018
# Released under the GNU GPL version 3
use strict;
use warnings;
use v5.14;
use Cwd 'abs_path';
my $help_text = "USAGE: seqswap out_dir out_prefix out_suffix in_1 [in_2 ...]
EXAMPLE: seqswap in out scan_ .png 2,4..:s:scans/left 1,3..:s:scans/right
This would take all files from in which have numbers in them, put the evenly
numbered ones into scans/left and odd into scans/right, re-numbering them
starting from scan_00001.png. Useful for reorganizing scanned books. \n";
my $out_digits = 5;
@ARGV >= 4 or die $help_text;
my ($rel_out_dir, $out_prefix, $out_suffix, @user_strs) = @ARGV;
# remove trailing slash if it exists
-d $rel_out_dir or die "Output directory \"$rel_out_dir\" does not exist.\n";
# automatically strips trailing slash
my $out_dir = abs_path $rel_out_dir;
=pod
Format for an input hash:
files => @all files individuall, not the folder!
start => the number to start at
interval => the number to increment by
overwrite => 1 if to overwrite, 0 if to skip to the next sequence item instead.
=cut
# returns a reference to the hash
sub user_str_2_input_hash {
my $user_str = shift;
$user_str =~ /(?<num_1>\d+)(,(?<num_2>\d+))?(?<repeat>\.\.)?:(?<overwrite>[os]):(?<path>.*)/ or die "Invalid user string: $user_str\n";
($+{num_2} and not $+{repeat}) and die "You may not specify an interval without repeat: $user_str\n";
my %input_hash = (
files => [],
);
$input_hash{start} = $+{num_1};
$input_hash{interval} = $+{num_2} ? $+{num_2} - $+{num_1} : $+{repeat} ? 1 : 0;
$input_hash{overwrite} = $+{overwrite} eq 'o';
-e $+{path} or die "Input path $+{path} does not exist.\n";
my $path = abs_path $+{path};
if (-d $path) {
opendir my $dir, $path or die "Failed to open directory $path";
# only files that have numbers in them, and sort. We assume same zero padding in each filename so vanilla sort is gucci
push @{$input_hash{files}}, map { "$path/$_" } sort grep { $_ =~ /\d+/ } readdir $dir;
closedir $dir or die "Failed to close directory $dir";
} else {
$path =~ /\d+/ or die "File $+{path} has no number in it.\n";
$input_hash{files}->[0] = $path;
}
return \%input_hash;
}
my @input_hashes = map { user_str_2_input_hash $_ } @user_strs;
# keys are the output number, values are the input filenames
my %out_nums = ();
for my $input_hash (@input_hashes) {
my $out_num = $input_hash->{start};
for my $file (@{$input_hash->{files}}) {
my $should_skip = ($out_nums{$out_num} and not $input_hash->{overwrite});
$out_nums{$out_num} = $file unless $should_skip;
# if only one number was specified on the command line, we're done.
last if $input_hash->{interval} == 0;
$out_num += $input_hash->{interval};
# keep the same file if we skipped
redo if $should_skip; # perl is so fucking nice
}
}
# ezpz
my $t = 0;
for my $out_num (keys %out_nums) {
# PERL IS SO FUCKIN SICK!
my $padded_out_num = '0' x ($out_digits - length $out_num) . $out_num;
my $out_filename = $out_dir . '/' . $out_prefix . $padded_out_num . $out_suffix;
symlink $out_nums{$out_num}, $out_filename or die "Failed to create symlink from $out_nums{$out_num} to $out_filename\n";
$t++;
}
say "Processed $t files without error.";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment