0

I have a list of paths stored in a bash variable, such as the following

>>> MY_PATHS= ../Some/Path/ ../Some/Other/../Path/

I'd like to have a list of unique relative paths, but due to the ".." parent directory used in the second path I can't just pipe these to uniq.

Is there a standard linux way to normalize directory paths?

My desired result is this:

>>> echo $MY_UNIQUE_PATHS
../Some/Path/
devnull
  • 118,548
  • 33
  • 236
  • 227
jozxyqk
  • 16,424
  • 12
  • 91
  • 180
  • `I'd like to have a list of unique relative paths` -- (1) It'd be easier to get absolute paths instead, (2) do these paths actually exist on the filesystem? – devnull Mar 12 '14 at 06:37
  • your desired output show only one, but input have three uniq address. why? – Farvardin Mar 12 '14 at 06:38
  • @devnull I'd like them to be relative as I commonly switch between machines and use sshfs mounts. Maybe get unique absolute paths and "relativeize" them after? Yes, the paths exist. – jozxyqk Mar 12 '14 at 06:39
  • 1
    @HomayounAfshari I want "unique" paths and have *two* addresses which both reference the same directory, hence a single output. – jozxyqk Mar 12 '14 at 06:41
  • 1
    (1) Use `readlink` for getting the absolute path. (2) Refer to [this question](http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory) for getting the relative path from the absolute one. – devnull Mar 12 '14 at 06:46
  • [This question](http://stackoverflow.com/questions/6643853/how-to-convert-in-path-names-to-absolute-name-in-a-bash-script) would help you with the first part. Now you're set for answering your own question! – devnull Mar 12 '14 at 06:47
  • 1
    In bash you may want [realpath(1)](http://man7.org/linux/man-pages/man1/realpath.1.html) – Basile Starynkevitch Mar 12 '14 at 08:07

2 Answers2

2

It seems python's relpath can do it all for me...

#!/usr/bin/python
import sys, os, pipes
paths = sys.argv[1:]                 #arguments are a list of paths
paths = map(os.path.relpath, paths)  #"normalize" and convert to a relative path
paths = set(paths)                   #remove duplicates
paths = map(pipes.quote, paths)      #for filenames with spaces etc
print " ".join(paths)                #print result

Examples:

>>> normpath ../Some/Path/ ../Some/Other/../Path/
../Some/Path
>>> normpath ../Some/Path/ ../Some/Other/../Different\ Path/
'../Some/Different Path' ../Some/Path

If absolute paths are wanted, replace relpath with abspath.

Thanks, @devnull!

jozxyqk
  • 16,424
  • 12
  • 91
  • 180
0

Here's a version just in bash, except for printing relative paths it still uses python's magical relpath function (see this).

Note: Paths must exist otherwise realpath fails :(

#!/usr/bin/bash

IFS=$'\r\n' #so the arrays abspaths and relpaths are created with just newlines

#expand to absolute paths and remove duplicates
abspaths=($(for p in "$@"; do realpath "$p"; done | sort | uniq))
printf "%q " "${abspaths[@]}" #use printf to escape spaces etc
echo #newline after the above printf

#use python to get relative paths
relpath(){ python -c "import os.path; print os.path.relpath('$1','${2:-$PWD}')" ; } 
relpaths=($(for p in "${abspaths[@]}"; do relpath "$p"; done))
printf "%q " "${relpaths[@]}"
echo
Community
  • 1
  • 1
jozxyqk
  • 16,424
  • 12
  • 91
  • 180