File: nls.sh 1 #!/bin/sh 2 3 # The MIT License (MIT) 4 # 5 # Copyright © 2025 pacman64 6 # 7 # Permission is hereby granted, free of charge, to any person obtaining a copy 8 # of this software and associated documentation files (the “Software”), to deal 9 # in the Software without restriction, including without limitation the rights 10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 # copies of the Software, and to permit persons to whom the Software is 12 # furnished to do so, subject to the following conditions: 13 # 14 # The above copyright notice and this permission notice shall be included in 15 # all copies or substantial portions of the Software. 16 # 17 # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 # SOFTWARE. 24 25 26 # nls [options...] [folders...] 27 # 28 # Nice LS runs `ls` to show files (and folders), then colors folders and links 29 # using ANSI styles to make things easier to scan/read. Long numbers are also 30 # made easier to read using alternating ANSI styles. 31 # 32 # To declutter the output, entries for same folders, the parent folders, and 33 # the totals are ignored from the `ls` results. 34 # 35 # Besides the usual `ls`-specific options, this script offers easier-to-use 36 # extra options, where leading double-dashes are also allowed: 37 # 38 # -group group folders and links separately from regular files 39 # -help show this help message 40 # -sort reverse-sort by size 41 42 43 case "$1" in 44 --h|-help|--help) 45 awk '/^# +nls /, /^$/ { gsub(/^# ?/, ""); print }' "$0" 46 exit 0 47 ;; 48 esac 49 50 list='ls -al --file-type --color=never --time-style iso' 51 52 for arg in "$@"; do 53 if [ "${arg}" = '--' ]; then 54 shift 55 break 56 fi 57 58 case "${arg}" in 59 -group|--group) 60 list="${list} --group-directories-first" 61 shift 62 continue 63 ;; 64 -sort|--sort) 65 list="${list} -S" 66 shift 67 continue 68 ;; 69 -*) 70 list="${list} ${arg}" 71 shift 72 continue 73 ;; 74 esac 75 76 break 77 done 78 79 options='-MKiCRS' 80 if [ $# -le 1 ]; then 81 options='--header=1 -MKiCRS' 82 fi 83 84 gap=0 85 86 for arg in "${@:-.}"; do 87 if [ -L "${arg}" ]; then 88 arg="$(realpath "${arg}")" 89 fi 90 if [ ! -d "${arg}" ]; then 91 continue 92 fi 93 94 [ "${gap}" -gt 0 ] && printf "\n" 95 printf "\e[7m%s\e[0m\n\n" "$(realpath "${arg}" || "${arg}")" 96 gap=1 97 98 ${list} "${arg}" | awk ' 99 BEGIN { 100 drep = "\x1b[38;2;0;135;255m\x1b[48;2;228;228;228m&\x1b[0m" 101 lrep = "\x1b[38;2;0;135;95m\x1b[48;2;228;228;228m&\x1b[0m" 102 } 103 104 / \.\.?\/$/ || /^total / { next } 105 106 { 107 gsub(/^(d[rwx-]+)/, drep) 108 gsub(/^(l[rwx-]+)/, lrep) 109 if (n % 5 == 0 && n > 0) print "" 110 printf "%6d %s\n", ++n, $0 111 } 112 ' | sed -E \ 113 -e 's-([0-9]{1,3})([0-9]{3})([0-9]{3})([0-9]{3})([0-9]{3})([0-9]{3})([0-9]{3})-\1\x1b[38;2;168;168;168m\2\x1b[0m\3\x1b[38;2;168;168;168m\4\x1b[0m\5\x1b[38;2;168;168;168m\6\x1b[0m\7-g' \ 114 -e 's-([0-9]{1,3})([0-9]{3})([0-9]{3})([0-9]{3})([0-9]{3})([0-9]{3})-\1\x1b[38;2;168;168;168m\2\x1b[0m\3\x1b[38;2;168;168;168m\4\x1b[0m\5\x1b[38;2;168;168;168m\6\x1b[0m-g' \ 115 -e 's-([0-9]{1,3})([0-9]{3})([0-9]{3})([0-9]{3})([0-9]{3})-\1\x1b[38;2;168;168;168m\2\x1b[0m\3\x1b[38;2;168;168;168m\4\x1b[0m\5-g' \ 116 -e 's-([0-9]{1,3})([0-9]{3})([0-9]{3})([0-9]{3})-\1\x1b[38;2;168;168;168m\2\x1b[0m\3\x1b[38;2;168;168;168m\4\x1b[0m-g' \ 117 -e 's-([0-9]{1,3})([0-9]{3})([0-9]{3})-\1\x1b[38;2;168;168;168m\2\x1b[0m\3-g' \ 118 -e 's-([0-9]{1,3})([0-9]{3})-\1\x1b[38;2;168;168;168m\2\x1b[0m-g' 119 done | less ${options}