#!/usr/bin/perl use warnings; use strict; use Data::Dumper qw/Dumper/; my %opts = ( a => [qw/1 2 3/], b => [qw/4 5 6/], c => [qw/foo bar baz/], ); # The work function should expect a hashref containing the values # for this run my $work = sub { my $hr = shift; print "A $hr->{a} B $hr->{b} C $hr->{c}\n"; }; run_all_perms(\%opts, $work); exit 0; sub run_all_perms { my $orig_opts = shift; my $work = shift; my %multi_opts = %$orig_opts; my @keys = sort keys %multi_opts; my $key = $keys[0]; # We don't want to pass this key on my $vals = delete $multi_opts{$key}; foreach my $val (@$vals) { if (keys %multi_opts) { # We have more perms to do my $new_work = sub { my $hr = shift; # Capture this arg in the hashref $hr->{$key} = $val; # Run the previous work function with the accumulated args $work->($hr); }; # Recurse with our accumulating work function run_all_perms(\%multi_opts, $new_work); } else { # We've captured all the args we need, let's go $work->({$key => $val}); } } }