good working version of acp
[small-misc-bash] / ll-function
1 #!/bin/bash
2 # Copyright (C) 2014 Ian Kelling
3
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16
17 ll() {
18 case $1 in
19 -h|--help)
20 cat <<'EOF'
21 usage: ll [ARGS_TO_LS]
22 ls -lA with enhanced output
23
24 octal permissions
25 omited acl type specifier
26 better hard link count: number of subdirectories or the
27 number of linked files or omitted if it is 0
28 better human readable size
29 more natural date/time format for my American raised eyes
30 remove first line size summary
31
32 /bin/ls output is below:
33
34 EOF
35 ;;
36 esac
37 local x y perm line binls sizePadding middle tail size \
38 max_hl_digits hardlinks initial_space hardlink_spacing
39 local max_hl_digits=0
40 local -a lines hl
41 binls=$(type -P ls)
42 local aclchar=false
43 # there's no way to tell if ls uses the acl specifier unless we loop over the data twice
44 # the 11th char is either
45 # . for selinux context
46 # + for any other kind of acl
47 # or blank for no other kind of acl
48 # I don't want to see this generally.
49 while read line; do
50 # if we did want the first line, it would need to be stripped of non-printing chars:
51 #line=${line#$'\E[00m'}
52 # lines like "total 123M", we don't want
53 if [[ ! $line =~ ^total\ [0-9][^\ ]*$ ]]; then
54 lines+=("$line")
55 if ! [[ $line == [-dscbl][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xtT]* ]]; then
56 hardlinks=
57 else
58 [[ ! ${line:10:1} == " " ]] && aclchar=true
59
60 # we also need to parse the hardlinks on the first pass, because for
61 # example ls could see the highest count as 11, and thus use 3
62 # places for hardlinks, " 10", but then we use 9 or 8 for a more
63 # useful count, and would then use 2 places. So we have to look
64 # through them all because we can't rely on the spacing that ls
65 # decided on.
66 y="${line:11}"
67 initial_space="${y%%[![:space:]]*}"
68 hardlinks="${y#$initial_space}" # remove any initial spaces
69 hardlinks="${hardlinks%%[[:space:]]*}" # remove everything beyond first word
70 # ignore the hardlinks that files/dirs always have
71 hardlinks=$(( hardlinks - 1 ))
72 [[ $hardlinks == 0 ]] && hardlinks=
73 if (( ${#hardlinks} > max_hl_digits )); then
74 max_hl_digits=${#hardlinks}
75 fi
76 fi
77 hl+=("$hardlinks")
78 fi
79 done< <( "$binls" -lAh --color=always "--time-style=+%m-%d %Y
80 %m-%d %I:%M %P" "$@" )
81
82 hardlink_spacing=$((max_hl_digits + 1))
83
84 for index in "${!lines[@]}"; do
85 line=${lines[index]}
86 hardlinks=${hl[index]}
87 if ! [[ $line == [-dscbl][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xtT]* ]]; then
88 printf "%s\n" "$line"
89 else
90 perm=0
91 for (( x=0; x<=8; x++ )); do
92 y=${line:$(( -1*x + 9 )):1}
93 [[ $y == [tT] ]] && perm=$(( perm + 512 ))
94 if [[ $y == [sS] ]]; then
95 [[ $x == 3 ]] && perm=$(( perm + 1024 ))
96 [[ $x == 6 ]] && perm=$(( perm + 2048 ))
97 fi
98 [[ $y != [-ST] ]] && perm=$(( perm + 2**x ))
99 done
100 if $aclchar; then
101 y="${line:11}"
102 else
103 y="${line:10}"
104 fi
105 middle=${y#*[^ ]* }
106 size=${middle#*[^ ]* *[^ ]* }
107 middle=${middle%"$size"}
108 tail=${size#*[^ ]* }
109 size=${size%"$tail"}
110 declare -i sizePadding="${#size} - 1"
111 size=( $size ) # remove spaces
112 size=${size/.?/}
113
114 printf "%s%4o%${hardlink_spacing}s%s%${sizePadding}s%s\n" \
115 "${line:0:1}" $perm "$hardlinks" " $middle" "$size" " $tail"
116 fi
117 done
118 }