use File::Spec::Unix (); sub remove_dot_dot { local $_ = $_[0]; $_ = File::Spec::Unix->canonpath($_); 1 while s#[^/]+/\.\./##g; s#/[^/]+/\.\.$#/#g; s#^[^/]+/\.\.$#.#g; return $_; } #### printf("%-20s -> %-20s\n", $_, remove_dot_dot($_)) foreach (qw( /foo/.. /foo/../bar foo/.. foo/../bar .. ../foo ../foo/bar foo/bar/../.. /foo/bar/../.. /foo/bar/../../moo /var/log/../../home/poletti/../../etc/passwd )); __END__ output ====== /foo/.. -> / /foo/../bar -> /bar foo/.. -> . foo/../bar -> bar .. -> .. ../foo -> ../foo ../foo/bar -> ../foo/bar foo/bar/../.. -> . /foo/bar/../.. -> / /foo/bar/../../moo -> /moo /var/log/../../home/poletti/../../etc/passwd -> /etc/passwd