#!/bin/bash # Copyright (C) 2014 Ian Kelling # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ll() { case $1 in -h|--help) cat <<'EOF' usage: ll [ARGS_TO_LS] ls -lA with enhanced output octal permissions omited acl type specifier better hard link count: number of subdirectories or the number of linked files or omitted if it is 0 better human readable size more natural date/time format for my American raised eyes remove first line size summary /bin/ls output is below: EOF ;; esac local x y perm line binls sizePadding middle tail size \ max_hl_digits hardlinks initial_space hardlink_spacing local max_hl_digits=0 local -a lines hl binls=$(type -P ls) local aclchar=false # there's no way to tell if ls uses the acl specifier unless we loop over the data twice # the 11th char is either # . for selinux context # + for any other kind of acl # or blank for no other kind of acl # I don't want to see this generally. while read line; do # if we did want the first line, it would need to be stripped of non-printing chars: #line=${line#$'\E[00m'} # lines like "total 123M", we don't want if [[ ! $line =~ ^total\ [0-9][^\ ]*$ ]]; then lines+=("$line") if ! [[ $line == [-dscbl][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xtT]* ]]; then hardlinks= else [[ ! ${line:10:1} == " " ]] && aclchar=true # we also need to parse the hardlinks on the first pass, because for # example ls could see the highest count as 11, and thus use 3 # places for hardlinks, " 10", but then we use 9 or 8 for a more # useful count, and would then use 2 places. So we have to look # through them all because we can't rely on the spacing that ls # decided on. y="${line:11}" initial_space="${y%%[![:space:]]*}" hardlinks="${y#$initial_space}" # remove any initial spaces hardlinks="${hardlinks%%[[:space:]]*}" # remove everything beyond first word # ignore the hardlinks that files/dirs always have hardlinks=$(( hardlinks - 1 )) [[ $hardlinks == 0 ]] && hardlinks= if (( ${#hardlinks} > max_hl_digits )); then max_hl_digits=${#hardlinks} fi fi hl+=("$hardlinks") fi done< <( "$binls" -lAh --color=always "--time-style=+%m-%d %Y %m-%d %I:%M %P" "$@" ) hardlink_spacing=$((max_hl_digits + 1)) for index in "${!lines[@]}"; do line=${lines[index]} hardlinks=${hl[index]} if ! [[ $line == [-dscbl][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xtT]* ]]; then printf "%s\n" "$line" else perm=0 for (( x=0; x<=8; x++ )); do y=${line:$(( -1*x + 9 )):1} [[ $y == [tT] ]] && perm=$(( perm + 512 )) if [[ $y == [sS] ]]; then [[ $x == 3 ]] && perm=$(( perm + 1024 )) [[ $x == 6 ]] && perm=$(( perm + 2048 )) fi [[ $y != [-ST] ]] && perm=$(( perm + 2**x )) done if $aclchar; then y="${line:11}" else y="${line:10}" fi middle=${y#*[^ ]* } size=${middle#*[^ ]* *[^ ]* } middle=${middle%"$size"} tail=${size#*[^ ]* } size=${size%"$tail"} declare -i sizePadding="${#size} - 1" size=( $size ) # remove spaces size=${size/.?/} printf "%s%4o%${hardlink_spacing}s%s%${sizePadding}s%s\n" \ "${line:0:1}" $perm "$hardlinks" " $middle" "$size" " $tail" fi done }