for my $testfn ( "a/b/c", 'a\b\c', 'a:b:c', "a[!{(\205)}!].ext", "a.ext", ){ printf "( %s )\n\t(%s)\n\n", $testfn , WashFilename( $testfn ); } sub WashFilename { use File::Basename; my $basename = basename( shift ); #~ $basename =~ s/[^a-zA-Z0-9]//g; # remove everything except a-z A-Z 0-9 $basename = join '', $basename =~ m/([.a-zA-Z0-9])/g; # untainted , only use a-z A-Z 0-9 and dot # basename is now, hopefully, file.ext ## so to ensure uniqueness, we adulterate it :) my $id = $$.'-'.time; my( $file, $ext ) = split /\./, $basename, 2 ; return join '.', grep defined, $file, $id, $ext; } __END__ ( a/b/c ) (c.1272-1316599567) ( a\b\c ) (c.1272-1316599567) ( a:b:c ) (c.1272-1316599567) ( a[!{(à)}!].ext ) (a.1272-1316599567.ext) ( a.ext ) (a.1272-1316599567.ext)