diff options
Diffstat (limited to 'shop')
-rwxr-xr-x | shop | 157 |
1 files changed, 157 insertions, 0 deletions
@@ -0,0 +1,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[@]}" |