diff --git a/README.md b/README.md
index df92817..dd0e8be 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ making the output prettier, more colorful, more compact, and easier to read.
showing the ping responses in a *graphical* way at the terminal (by using
colors and Unicode characters).
-`prettyping` is written in `bash` and `awk`, and is reported to work on many
+`prettyping` is written in `sh` and `awk`, and is reported to work on many
different systems (Linux, Mac OS X, BSD…), as well as running on different
versions of `awk` (`gawk`, `mawk`, `nawk`, `busybox awk`).
@@ -20,7 +20,7 @@ screenshots, videos at:
Requirements
------------
-* `bash` (tested on 4.20, should work on versions as old as 2008)
+* posix-compatible shell, e.g. `bash` or `dash`
* `awk` (either [gawk][], [mawk][], [nawk][] or [busybox awk][]; should work on
`gawk` versions as old as 2008; should probably work on any other awk
implementation)
@@ -35,7 +35,7 @@ Installation
2. Make it executable: `chmod +x prettyping`
That's all! No root permission is required. You can save and run it from any
-directory. As long as your user can run `ping`, `bash` and `awk`, then
+directory. As long as your user can run `ping`, `sh` and `awk`, then
`prettyping` will work.
Alternatively, you can download the latest tarball from GitHub: [](https://github.com/denilsonsa/prettyping/releases/latest)
diff --git a/mockping.sh b/mockping.sh
index 9d13bbf..a041a26 100755
--- a/mockping.sh
+++ b/mockping.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
#
# This is just a mock ping program that reproduces the same output all the
# time. It is used for testing/developing prettyping.
@@ -8,6 +8,7 @@ sample_output() {
PING registro.br (200.160.2.3) 56(84) bytes of data.
Request timeout for icmp_seq 1
64 bytes from registro.br (200.160.2.3): icmp_seq=2 ttl=56 time=25.5 ms
+SIGWINCH
64 bytes from registro.br (200.160.2.3): icmp_seq=3 ttl=56 time=55.7 ms
64 bytes from registro.br (200.160.2.3): icmp_seq=4 ttl=56 time=75.2 ms
ping: sendto: Network is down
@@ -49,7 +50,13 @@ rtt min/avg/max/mdev = 36.750/38.535/40.048/1.360 ms
EOF
}
-sample_output | while read line; do
- echo -E "$line"
- sleep 0.25s
+pgid=$(ps -o pgid= $$ | tr -d '[:space:]')
+
+sample_output | while read -r line; do
+ if [ "$line" = "SIGWINCH" ]; then
+ kill -WINCH -- -"$pgid"
+ continue
+ fi
+ printf '%s\n' "$line"
+ sleep "${SLEEP_SECS:-0.25}"
done
diff --git a/prettyping b/prettyping
index b6e7881..9fa2995 100755
--- a/prettyping
+++ b/prettyping
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/bin/sh
#
# Written by Denilson Figueiredo de Sá
# MIT license
@@ -78,172 +78,157 @@ All other parameters are passed directly to ping.
EOF
}
+MYNAME=$(basename "$0")
+
# Thanks to people at #bash who pointed me at
# https://web.archive.org/web/20100301171512/https://bash-hackers.org/wiki/doku.php/scripting/posparams
-parse_arguments() {
- USE_COLOR=1
- USE_MULTICOLOR=1
- USE_UNICODE=1
- USE_LEGEND=1
- USE_GLOBALSTATS=1
- USE_RECENTSTATS=1
-
- if [ -t 1 ]; then
- IS_TERMINAL=1
- else
- IS_TERMINAL=0
- fi
-
- LAST_N=60
- OVERRIDE_COLUMNS=0
- OVERRIDE_LINES=0
- RTT_MIN=auto
- RTT_MAX=auto
-
- PING_BIN="ping"
- #PING_BIN="./mockping.awk"
- PING_PARAMS=( )
-
- AWK_BIN="awk"
- AWK_PARAMS=( )
-
- while [[ $# != 0 ]] ; do
- case "$1" in
- -h | -help | --help )
- print_help
- exit
- ;;
-
- # Forbidden ping parameters within prettyping:
- -f )
- echo "${MYNAME}: You can't use the -f (flood) option."
- exit 1
- ;;
- -R )
- # -R prints extra information at each ping response.
- echo "${MYNAME}: You can't use the -R (record route) option."
- exit 1
- ;;
- -q )
- echo "${MYNAME}: You can't use the -q (quiet) option."
- exit 1
- ;;
- -v )
- # -v enables verbose output. However, it seems the output with
- # or without this option is the same. Anyway, prettyping will
- # strip this parameter.
- ;;
- # Note:
- # Small values for -s parameter prevents ping from being able to
- # calculate RTT.
-
- # New parameters:
- -a )
- # TODO: Implement audible ping for responses or for missing packets
- ;;
-
- -color | --color ) USE_COLOR=1 ;;
- -nocolor | --nocolor ) USE_COLOR=0 ;;
- -multicolor | --multicolor ) USE_MULTICOLOR=1 ;;
- -nomulticolor | --nomulticolor ) USE_MULTICOLOR=0 ;;
- -unicode | --unicode ) USE_UNICODE=1 ;;
- -nounicode | --nounicode ) USE_UNICODE=0 ;;
- -legend | --legend ) USE_LEGEND=1 ;;
- -nolegend | --nolegend ) USE_LEGEND=0 ;;
- -globalstats | --globalstats ) USE_GLOBALSTATS=1 ;;
- -noglobalstats | --noglobalstats ) USE_GLOBALSTATS=0 ;;
- -recentstats | --recentstats ) USE_RECENTSTATS=1 ;;
- -norecentstats | --norecentstats ) USE_RECENTSTATS=0 ;;
- -terminal | --terminal ) IS_TERMINAL=1 ;;
- -noterminal | --noterminal ) IS_TERMINAL=0 ;;
-
- -awkbin | --awkbin ) AWK_BIN="$2" ; shift ;;
- -pingbin | --pingbin ) PING_BIN="$2" ; shift ;;
-
- #TODO: Check if these parameters are numbers.
- -last | --last ) LAST_N="$2" ; shift ;;
- -columns | --columns ) OVERRIDE_COLUMNS="$2" ; shift ;;
- -lines | --lines ) OVERRIDE_LINES="$2" ; shift ;;
- -rttmin | --rttmin ) RTT_MIN="$2" ; shift ;;
- -rttmax | --rttmax ) RTT_MAX="$2" ; shift ;;
-
- * )
- PING_PARAMS+=("$1")
- ;;
- esac
+USE_COLOR=1
+USE_MULTICOLOR=1
+USE_UNICODE=1
+USE_LEGEND=1
+USE_GLOBALSTATS=1
+USE_RECENTSTATS=1
+
+if [ -t 1 ]; then
+ IS_TERMINAL=1
+else
+ IS_TERMINAL=0
+fi
+
+LAST_N=60
+OVERRIDE_COLUMNS=0
+OVERRIDE_LINES=0
+RTT_MIN=0
+RTT_MAX=0
+
+PING_BIN="ping"
+#PING_BIN="./mockping.sh"
+
+AWK_BIN="awk"
+
+skipnext=0
+for arg; do
+ if [ "$skipnext" -eq 1 ]; then
+ skipnext=0
shift
- done
-
- if [[ "${RTT_MIN}" -gt 0 && "${RTT_MAX}" -gt 0 && "${RTT_MIN}" -ge "${RTT_MAX}" ]] ; then
- echo "${MYNAME}: Invalid --rttmin and -rttmax values."
- exit 1
+ continue
fi
+ case "$1" in
+ -h | -help | --help )
+ print_help
+ exit
+ ;;
+
+ # Forbidden ping parameters within prettyping:
+ -f )
+ echo "${MYNAME}: You can't use the -f (flood) option."
+ exit 1
+ ;;
+ -R )
+ # -R prints extra information at each ping response.
+ echo "${MYNAME}: You can't use the -R (record route) option."
+ exit 1
+ ;;
+ -q )
+ echo "${MYNAME}: You can't use the -q (quiet) option."
+ exit 1
+ ;;
+ -v )
+ # -v enables verbose output. However, it seems the output with
+ # or without this option is the same. Anyway, prettyping will
+ # strip this parameter.
+ ;;
+ # Note:
+ # Small values for -s parameter prevents ping from being able to
+ # calculate RTT.
+
+ # New parameters:
+ -a )
+ # TODO: Implement audible ping for responses or for missing packets
+ ;;
+
+ -color | --color ) USE_COLOR=1 ;;
+ -nocolor | --nocolor ) USE_COLOR=0 ;;
+ -multicolor | --multicolor ) USE_MULTICOLOR=1 ;;
+ -nomulticolor | --nomulticolor ) USE_MULTICOLOR=0 ;;
+ -unicode | --unicode ) USE_UNICODE=1 ;;
+ -nounicode | --nounicode ) USE_UNICODE=0 ;;
+ -legend | --legend ) USE_LEGEND=1 ;;
+ -nolegend | --nolegend ) USE_LEGEND=0 ;;
+ -globalstats | --globalstats ) USE_GLOBALSTATS=1 ;;
+ -noglobalstats | --noglobalstats ) USE_GLOBALSTATS=0 ;;
+ -recentstats | --recentstats ) USE_RECENTSTATS=1 ;;
+ -norecentstats | --norecentstats ) USE_RECENTSTATS=0 ;;
+ -terminal | --terminal ) IS_TERMINAL=1 ;;
+ -noterminal | --noterminal ) IS_TERMINAL=0 ;;
+
+ -awkbin | --awkbin ) AWK_BIN="$2" ; skipnext=1 ;;
+ -pingbin | --pingbin ) PING_BIN="$2" ; skipnext=1 ;;
+
+ #TODO: Check if these parameters are numbers.
+ -last | --last ) LAST_N="$2" ; skipnext=1 ;;
+ -columns | --columns ) OVERRIDE_COLUMNS="$2" ; skipnext=1 ;;
+ -lines | --lines ) OVERRIDE_LINES="$2" ; skipnext=1 ;;
+ -rttmin | --rttmin ) RTT_MIN="$2" ; skipnext=1 ;;
+ -rttmax | --rttmax ) RTT_MAX="$2" ; skipnext=1 ;;
+
+ * )
+ # unprocessed parameters will cycle to the front of $@ to be passed to `ping`
+ set -- "$@" "$1"
+ ;;
+ esac
+ shift
+done
+
+if [ "${RTT_MIN}" -gt 0 ] && [ "${RTT_MAX}" -gt 0 ] && [ "${RTT_MIN}" -ge "${RTT_MAX}" ] ; then
+ echo "${MYNAME}: Invalid --rttmin and -rttmax values."
+ exit 1
+fi
+
+if [ $# -eq 0 ] ; then
+ echo "${MYNAME}: Missing parameters, use --help for instructions."
+ exit 1
+fi
+
+# Workaround for mawk:
+# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593504
+awk_version="$(echo | "${AWK_BIN}" -W version 2>&1)"
+case "$awk_version" in
+ mawk*) AWK_PARAMS="-W interactive" ;;
+esac
- if [[ "${#PING_PARAMS[@]}" = 0 ]] ; then
- echo "${MYNAME}: Missing parameters, use --help for instructions."
- exit 1
- fi
- # Workaround for mawk:
- # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593504
- local version="$(echo | "${AWK_BIN}" -W version 2>&1)"
- if [[ "${version}" == mawk* ]] ; then
- AWK_PARAMS+=(-W interactive)
- fi
-}
-
-MYNAME=`basename "$0"`
-parse_arguments "$@"
export LC_ALL=C
-# Warning! Ugly code ahead!
-# The code is so ugly that the comments explaining it are
-# bigger than the code itself!
-#
-# Suppose this:
-#
-# cmd_a | cmd_b &
-#
-# I need the PID of cmd_a. How can I get it?
-# In bash, $! will give me the PID of cmd_b.
-#
-# So, I came up with this ugly solution: open a subshell, like this:
-#
-# (
-# cmd_a &
-# echo "This is the PID I want $!"
-# wait
-# ) | cmd_b
-
+# Ignore SIGINT (Ctrl-C) downstream of ping, so the pipeline can cleanly finish when ping is interrupted.
-# Ignore Ctrl+C here.
-# If I don't do this, this shell script is killed before
-# ping and gawk can finish their work.
-trap '' 2
+"${PING_BIN}" "$@" 2>&1 | (
+ trap '' INT
-# Now the ugly code.
-(
- "${PING_BIN}" "${PING_PARAMS[@]}" &
- PING_PID="$!"
-
- # Commented out, because it looks like this line is not needed
- #trap "kill -2 $PING_PID ; exit 1" 2 # Catch Ctrl+C here
-
- wait
-) 2>&1 | (
if [ "${IS_TERMINAL}" = 1 ]; then
# Print a message to notify the awk script about terminal size change.
- trap "echo SIGWINCH" 28
+ trap 'sigwinch=1; echo SIGWINCH' WINCH
fi
- # The trap must be in another subshell because otherwise it will interrupt
- # the "wait" commmand.
- while read line; do
- echo -E "$line"
+ sigwinch=0
+ while true; do
+ if ! read -r line; then
+ # some shells will interrupt read for the SIGWINCH, in which case we need to restart it
+ if [ "$sigwinch" -eq 1 ]; then
+ sigwinch=0
+ continue
+ else
+ break
+ fi
+ fi
+ printf '%s\n' "$line"
done
-) 2>&1 | "${AWK_BIN}" "${AWK_PARAMS[@]}" '
+) 2>&1 | (
+ trap '' INT
+
+ "${AWK_BIN}" ${AWK_PARAMS:+$AWK_PARAMS} '
# Weird that awk does not come with abs(), so I need to implement it.
function abs(x) {
return ( (x < 0) ? -x : x )
@@ -478,12 +463,12 @@ function print_received_response(rtt, block_index) {
} else {
block_index = 1 + int((rtt - BLOCK_RTT_MIN) * (BLOCK_LEN - 2) / BLOCK_RTT_RANGE)
}
- printf( BLOCK[block_index] )
+ printf( BLOCK[block_index] ESC_DEFAULT )
CURR_COL++
}
function print_missing_response(rtt) {
- printf( ESC_RED "!" )
+ printf( ESC_RED "!" ESC_DEFAULT )
CURR_COL++
}
@@ -889,3 +874,4 @@ BEGIN {
# Not needed when the output is a terminal, but does not hurt either.
fflush()
}'
+)