1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
#!/bin/bash
#
# shop - Show Permissions at all levels of a given path
#
# With `tree(1)` you start at a trunk and show all leaves that
# originate from that trunk, optionally showing permissions.
# `shop` starts at a leaf and shows the permissions back to a
# trunk.
#
# CREATED: 2009-09-03 17:30
# MODIFIED: 2009-11-17 11:05
_NAME=$(basename $0)
_VERSION=1.0
# DEFAULTS
unset octal # use text mode instead of octal mode
level=-1 # traverse all the way up to /
trunk='/' # traverse all the way up to /
pad=17 # padding for pathname
usage() {
cat <<EOT
Usage: $_NAME [-L N] [-o] [-t PATH] [PATH1..]
Options:
-L, --level N traverse N levels up the tree
-o, --octal show octal mode instead of human readable mode
-t, --trunk PATH only traverse up to PATH instead of / (root)
- takes precedence over --level
-p, --pad N allow USER:GROUP N characters before directory name
default: 17
-h, --help show this message
--version show version info
EOT
}
_shop() {
[ $octal ] && stat_str="%a" || stat_str="%A"
stats=( $(stat -c "$stat_str %U:%G %n" "$1") )
if [ $octal ]; then
# `stat -c "%a"` only returns a 4 digit mode when the first digit is
# nonzero, yet `stat` always returns a 4 digit mode. how annoying...
[ ${#stats} -eq 3 ] && echo -n "0"
fi
printf "%s %-${pad}s ${stats[@]:2}\n" "${stats[@]:0:2}"
}
main() {
arg="$1"
if [ -z "$arg" ]; then
# user didn't supply an arg, use current working dir
arg="$PWD"
fi
until [ -z "$arg" ]; do
if ! [ -a "$arg" ]; then
echo "error: $arg does not exist"
return 1
fi
# if $arg is a directory, prime the directory stack, else use
# the parent dir of $arg to prime the stack
if [ -d "$arg" ]; then
cd "$arg" || return 1
unset file_arg
else
cd $(dirname -- "$arg") || return 1
file_arg=1
let "level -=1"
fi
start_dir=$PWD
# populate directory stack with $level levels on the path to
# the $trunk
while [ "$PWD" != "$trunk" ]; do
if [ $level -gt 0 ] || [ $level -lt 0 ]; then
let "level -= 1"
pushd .. &> /dev/null
elif [ $level -eq 0 ]; then
break;
fi
done
# display the permissions for each level
while [ "$PWD" != "$start_dir" ]; do
_shop "$PWD"
popd &> /dev/null
done
_shop "$PWD"
# leaf was a file, run _shop on this file as well
if [ $file_arg ]; then
_shop "${PWD}/$(basename -- "$arg")"
else
cd .. || return 1
fi
# user passed multiple leafs, separate output for each leaf
if [ $# -gt 1 ]; then
echo
fi
shift
arg="$1"
done
}
declare -a args
until [ -z "$1" ]; do
case "$1" in
-L|--level) level="$2"
shift 2
;;
-o|--octal) octal=1
shift
;;
-t|--trunk) trunk="$(readlink -f $2)"
shift 2
;;
-p|--pad) pad="$2"
shift 2
;;
-h|--help) usage
exit
;;
--version) echo "$_NAME v$_VERSION"
exit
;;
--) shift
args=( "${args[@]}" "$@" )
break
;;
-*) echo -e "$_NAME: unknown option: $1\n"
usage
exit
;;
*) args[${#args[*]}]="$1"
shift
;;
esac
done
main "${args[@]}"
|