sub dive_val :lvalue { my $p = \shift; $p = \( $$p->{$_} ) for @_; $$p } my @paths = ('key1', 'key2:key22', 'key2:key23'); for my $path (@paths) { my @path = split(/:/, $path); my $new_val = ...; dive_val(\%hash, @path) = $new_val; }