/ contrib / shell / realpath.bash
realpath.bash
 1  #!/usr/bin/env bash
 2  
 3  # Based on realpath.sh written by Michael Kropat
 4  # Found at: https://github.com/mkropat/sh-realpath/blob/65512368b8155b176b67122aa395ac580d9acc5b/realpath.sh
 5  
 6  bash_realpath() {
 7      canonicalize_path "$(resolve_symlinks "$1")"
 8  }
 9  
10  resolve_symlinks() {
11      _resolve_symlinks "$1"
12  }
13  
14  _resolve_symlinks() {
15      _assert_no_path_cycles "$@" || return
16  
17      local dir_context path
18      if path=$(readlink -- "$1"); then
19          dir_context=$(dirname -- "$1")
20          _resolve_symlinks "$(_prepend_dir_context_if_necessary "$dir_context" "$path")" "$@"
21      else
22          printf '%s\n' "$1"
23      fi
24  }
25  
26  _prepend_dir_context_if_necessary() {
27      if [ "$1" = . ]; then
28          printf '%s\n' "$2"
29      else
30          _prepend_path_if_relative "$1" "$2"
31      fi
32  }
33  
34  _prepend_path_if_relative() {
35      case "$2" in
36          /* ) printf '%s\n' "$2" ;;
37           * ) printf '%s\n' "$1/$2" ;;
38      esac
39  }
40  
41  _assert_no_path_cycles() {
42      local target path
43  
44      target=$1
45      shift
46  
47      for path in "$@"; do
48          if [ "$path" = "$target" ]; then
49              return 1
50          fi
51      done
52  }
53  
54  canonicalize_path() {
55      if [ -d "$1" ]; then
56          _canonicalize_dir_path "$1"
57      else
58          _canonicalize_file_path "$1"
59      fi
60  }
61  
62  _canonicalize_dir_path() {
63      (cd "$1" 2>/dev/null && pwd -P)
64  }
65  
66  _canonicalize_file_path() {
67      local dir file
68      dir=$(dirname -- "$1")
69      file=$(basename -- "$1")
70      (cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file")
71  }