File: np.sh
   1 #!/bin/sh
   2 
   3 # The MIT License (MIT)
   4 #
   5 # Copyright © 2020-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 # np [options...]
  27 #
  28 # Nice Processes shows all current processes using ANSI styles to make
  29 # things easier to scan/read. To get the process info, the standard `ps`
  30 # command is used: when not given any options, `ps aux` is the default.
  31 #
  32 # The options are the same as those for `ps`, as well as any of `-h`, `--h`,
  33 # `-help`, or `--help`, to show this help message.
  34 
  35 
  36 case "$1" in
  37     -h|--h|-help|--help)
  38         awk '/^# +np /, /^$/ { gsub(/^# ?/, ""); print }' "$0"
  39         exit 0
  40     ;;
  41 esac
  42 
  43 res="$(ps "${@:-aux}")"
  44 code=$?
  45 if [ "${code}" -ne 0 ]; then
  46     return "${code}"
  47 fi
  48 
  49 echo "${res}" |
  50 
  51 # restyle numbers with at least 4 digits to make them easier to read; ignore
  52 # numbers in the command fields at the end of lines
  53 awk '
  54     /COMMAND$/ && cut == 0 {
  55         match($0, /COMMAND$/)
  56         cut = RSTART
  57     }
  58 
  59     {
  60         s = (cut > 0) ? substr($0, 1, cut - 1) : $0
  61 
  62         # restyle digit-runs which are longer than 3
  63         while (match(s, /[0-9]{4,}/)) {
  64             # give up on digit-runs which are unusually long, to mitigate the
  65             # quadratic time-complexity of slicing strings in a loop
  66             if (RLENGTH > 1000) {
  67                 printf "%s", substr(s, 1, RSTART + RLENGTH)
  68                 s = substr(s, RSTART + RLENGTH)
  69                 continue
  70             }
  71 
  72             len = RLENGTH
  73             lead = len % 3
  74             alt = lead > 0
  75 
  76             printf "%s", substr(s, 1, RSTART + lead - 1)
  77             s = substr(s, RSTART + lead)
  78             len -= lead
  79 
  80             while (len > 0) {
  81                 triple = substr(s, 1, 3)
  82                 if (alt == 1) {
  83                     printf "\x1b[38;2;168;168;168m%s\x1b[0m", triple
  84                 } else {
  85                     printf "%s", triple
  86                 }
  87 
  88                 alt = 1 - alt
  89                 s = substr(s, 4)
  90                 len -= 3
  91             }
  92         }
  93 
  94         if (cut > 0) {
  95             printf "%s%s\n", s, substr($0, cut); fflush()
  96         } else {
  97             printf "%s\n", s; fflush()
  98         }
  99     }
 100 ' |
 101 
 102 # add a header line with the current time/date; style lines where root is the
 103 # user differently; make 0 values stand out in any line
 104 awk '
 105     BEGIN {
 106         d = strftime("%a %b %d")
 107         t = strftime("%H:%M:%S")
 108         # printf "\x1b[7m%30s%s  %s%30s\x1b[0m\n\n", "", d, t, ""
 109         fmt = "\x1b[38;2;128;128;128m\x1b[7m%30s%s  %s%30s\x1b[0m\n\n"
 110         printf fmt, "", d, t, ""
 111     }
 112 
 113     (NR - 1) % 5 == 1 && NR > 1 { print "" }
 114 
 115     $1 == "root" {
 116         gsub(/^/, "\x1b[38;2;52;101;164m")
 117         gsub(/ +/, "&\x1b[0m\x1b[38;2;52;101;164m")
 118         gsub(/$/, "\x1b[0m")
 119     }
 120 
 121     {
 122         gsub(/0\.00*/, "\x1b[38;2;135;135;175m&\x1b[0m")
 123         gsub(/0:00/, "\x1b[38;2;135;135;175m&\x1b[0m")
 124         printf "%3d  %s\n", NR - 1, $0
 125     }
 126 ' |
 127 
 128 less -JMKiCRS