bugfixes, features, documentation, examples, new tool
[hband-tools.git] / user-tools / symlinks-analyze
blob5b33ab69db84cee468ab8d23ae91736f6f171281
1 #!/bin/bash
3 true <<EOF
4 =pod
6 =head1 NAME
8 symlinks-analyze - Discover where symlinks point at, recursively
10 =cut
12 EOF
15 set -e
16 set -u
17 . /usr/lib/tool/bash-utils
18 shopt -s extglob
19 unset CDPATH
20 unset CDPATH
21 set +e
23 notrailingslash()
25 local x=$1
26 if [ "$x" = / ]; then echo /; return; fi
27 echo ${x/%+(\/)/}
30 show_abs_path()
32 local path=$1 logical_path=$2
33 if [ $show_abs_path ]
34 then
35 if [ "${path:0:1}" = / ]
36 then
37 return
39 echo -n " [$logical_path]"
43 show_realpath()
45 local path=$1
46 if [ $show_realpath ]
47 then
48 local realpath=`readlink -n -f "$path"`
49 if [ "$realpath" != "$path" ]
50 then
51 echo -n " ($realpath)"
56 logical_dirname()
58 local path=$1
59 local dir=$(dirname "$path")
60 cd "$dir" && pwd || kill -ABRT $$
61 # kill ourself to prevent bad data at the caller,
62 # so the caller does not need to set errexit
65 logical_path()
67 local path=$1
68 local dirname=`logical_dirname "$path"`
69 if [ "$dirname" != / ]; then dirname=$dirname/; fi
70 local basename=$(basename "$path")
71 echo "$dirname$basename"
75 show_abs_path=''
76 show_realpath=''
77 show_parents=''
78 skip_non_symlinks=''
81 while [ $# -gt 0 ]
83 case "$1" in
84 --) shift; break;;
85 --help)
86 echo "Usage: symlinks-analyze [OPTIONS] <PATH> [<PATH> [...]]"
87 echo "OPTIONS:"
88 echo " -a, --absolute-path shown in [ brackets ]"
89 echo " -r, --real-path shown in ( brackets )"
90 echo " -p, --parents analyze parent directories of any traversed path too"
91 echo " -s, --skip-non-symlinks"
92 exit;;
93 -a|--abs|--absolute|--abs-path|--absolute-path)
94 show_abs_path=1;;
95 -p|--parent|--parents)
96 show_parents=1;;
97 -r|--realpath|--real-path)
98 show_realpath=1;;
99 -s|--skip-non-symlinks)
100 skip_non_symlinks=1;;
101 -*) echo "$0: unknown option: $1" >&2
102 exit -1;;
103 *) break;;
104 esac
105 shift
106 done
109 declare -a paths_to_analyze=("$@")
110 declare -a paths_analyzed=()
111 starting_wd=`pwd`
113 while [ ${#paths_to_analyze[@]} -gt 0 ]
115 declare -a visited=()
116 show_this_analysis=yes
118 path_to_analyze=${paths_to_analyze[0]}
119 path=`notrailingslash "$path_to_analyze"`
121 if [ $skip_non_symlinks ]
122 then
123 if [ ! -L "$path" ]
124 then
125 show_this_analysis=no
129 if [ ! -e "$path" -a ! -L "$path" ]
130 then
131 # neither an actual existing file nor a broken symlink
132 warnx "$path: not found"
133 show_this_analysis=no
136 if [ $show_this_analysis = yes ]
137 then
138 echo -n "$path"
140 logical_path=`logical_path "$path"`
141 show_abs_path "$path" "$logical_path"
142 show_realpath "$path"
143 visited+=("$logical_path")
145 while true
147 if [ $show_parents ]
148 then
149 parent=`logical_dirname "$path"`
150 if [ "$parent" != / ]
151 then
152 if ! in_list "$parent" "${paths_to_analyze[@]}" "${paths_analyzed[@]}"
153 then
154 paths_to_analyze+=("$parent")
159 if [ ! -L "$path" ]
160 then
161 break
164 set -e
165 target=`readlink "$path"`
166 dir=`dirname "$path"`
167 cd "$dir"
168 set +e
170 echo -n " -> $target"
171 logical_path=`logical_path "$target"`
172 show_abs_path "$target" "$logical_path"
174 if in_list "$logical_path" "${visited[@]}"
175 then
176 break
178 visited+=("$logical_path")
180 path=$target
181 path=`notrailingslash "$path"`
182 done
184 echo ";"
187 set -e
188 cd "$starting_wd"
189 set +e
191 array_shift paths_to_analyze >/dev/null
192 paths_analyzed+=("$path_to_analyze")
193 done