#!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11145493 use warnings; for my $path ( qw( /a/b/c/d/../../../e /a/../b/./c//d ../invalid_do_not_change ./tmp /tmp/../../../tmp A//B A/B/ A/./B A/foo/../B ) ) { local $_ = $path; 1 while s{ /+(?=/) | # multiple /// ^/..(?=/) | # stay at root /\z | # remove trailing / (?<=/)(?!\.\./)[^/]+/\.\./ | # remove 'name/../' (? %s\n", $path, $_; } #### /a/b/c/d/../../../e -> /a/e /a/../b/./c//d -> /b/c/d ../invalid_do_not_change -> ../invalid_do_not_change ./tmp -> tmp /tmp/../../../tmp -> /tmp A//B -> A/B A/B/ -> A/B A/./B -> A/B A/foo/../B -> A/B