刺身さんお久しぶりです^^;
local を使ってこんな再帰はどうでしょうか?^^;
local なのでグローバル変数を再帰のスタック上でしか書き換えないので、比較的安心です。
use strict; use Data::Dumper; sub hash_recursively { my $category = shift; my $category_name = shift || 'category_global'; # 再帰の中で最初の一回だけ [] が作られる # local なので、再帰を抜けると消える local $main::_links = $main::_links || []; while (my($key, $value) = each %$category) { # category だったら if (ref($value)) { hash_recursively($value, $key); } # category じゃなかったら else { push(@$main::_links, [$key, $value, $category_name]); } } return $main::_links; } # 以下テスト my $links = hash_recursively({ category_a => { bookmark_a => 'http://hoge.org', bookmark_b => 'http://fuga.org', }, category_b => { bookmark_c => 'http://hoge.com', bookmark_d => 'http://fuga.com', category_c => { bookmark_e => 'http://hoge.net', bookmark_f => 'http://fuga.net', }, category_d => { bookmark_g => 'http://hoge.jp', bookmark_h => 'http://fuga.jp', }, }, }); print Dumper($links);