Skip to content

Instantly share code, notes, and snippets.

@aberezin
Last active October 28, 2020 05:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save aberezin/a0cdec3c125851a96d4281183b6dd427 to your computer and use it in GitHub Desktop.
Save aberezin/a0cdec3c125851a96d4281183b6dd427 to your computer and use it in GitHub Desktop.
#! /usr/bin/env bash
# Use at own risk. License CC0 see https://creativecommons.org/publicdomain/mark/1.0/
# alanberezin.com
OPTIND=1 # Reset in case getopts has been used previously in the shell.
opt_stripclasspath=false
while getopts ":hc" opt; do
case "$1" in
-h | --help )
cat <<-EOF
Usage: ps [any-ps-options] | psjson [-c] [repeat-ps-options-see-below]
or: docker ps [any-docker-ps-options] | psjson [-c]
or: psjson -h
Reading the stdin, jsonify the output of ps (or docker ps). If you pipe the contents of "ps"
directly into psjson, then you do not need to repeat the ps options to psjon.
However, if you pipe the output of ps though grep, or anything else, that strips the
header off the output, then you need to repeat the ps options (like, -f) that would
have the effect of changing the default columns that are output Also, if you pipe
though grep or other commands that colorize, use the --color=never option to grep.
-c For ps(1) rows that have a "-cp" in the command string, remove the following
token. This effectively strips nuesance long java classpaths that clutter the output.
A nice feature of psjon is that it tokenizes the CMD column of ps. this is handy when, for example, the process is a java server with a mile long classpath.
For docker ps, the parsing of CREATED and STATUS needs work
Examples:
Correct: ps -f | grep foo | psjson -f
Correct: ps -ef | grep foo | psjson -f #dont need to repeat the -e flag
#it doesnt effect the header
Correct: ps -f | psjson
Correct: ps -f | psjson -f #final -f is ignored
Incorrect: ps -f | grep --color=never foo | psjson #wrong unless foo was a column header in ps
marginal: ps | grep foo | psjson #should use grep --color=never to be safe
This cmd requires that jq be installed. See https://stedolan.github.io/jq/manual/v1.4/
EOF
exit 0
;;
-c )
opt_stripclasspath=true
shift
;;
esac
done
#In case output of ps has no header (like if it was grep'd out)
#Note: test for header is an imperfect test which relies on PID in the header, maybe improve
tmpfile=$(mktemp)
trap 'rm -f $tmpfile' EXIT
cat > $tmpfile
# read -e -p 'debug> ' < /dev/tty
if cat "$tmpfile" | head -1 | grep --color=never ' PID ' > /dev/null ; then
:
elif cat "$tmpfile" | head -1 | grep --color=never 'CONTAINER' > /dev/null ; then
# A docker ps output. Reqrite header to avoid whitespace.
#TODO ceated and status fields still have embedded whitespace
header="CONTAINER_ID IMAGE COMMAND CREATED STATUS PORTS NAMES"
sed -i '1s/^/'"$header"'\n/
2d' $tmpfile
else
header="$(ps $@ | head -1)"
sed -i '1s;^;'"$header"'\n;' $tmpfile
fi
arg_separator='_-_-' #something unique bc we may need to split on it later
# Credit to https://unix.stackexchange.com/a/243485/103690 for the basic idea.
jq='
[sub("\n$";"") | splits("\n") | sub("^ +";"") | [splits(" +")]]
| .[0] as $orig_header
| [$orig_header[], (range(1000) | tostring | "arg'$arg_separator'"+.)] as $newheader
| .[1:] | [.[] | [. as $x | range($newheader | length)
| {"key": $newheader[.], "value": $x[.]}] | from_entries]
| del(.[][] | select(. == null))
'
if [ "$opt_stripclasspath" = true ] ; then
jq=$jq'
| .[] | . as $process | keys[] | select($process[.] == "-cp")
| split("_-_-")[1] | tonumber as $argnumber | $process
| del( .["arg_-_-" + (($argnumber+1) | tostring)]) | [.]'
fi
echo $jq > jq.tmp
cat $tmpfile | jq -sR "$jq"
@aberezin
Copy link
Author

aberezin commented Aug 22, 2018

convert ps output to JSON and tokenize the CMD column into separate key/val pairs.
This also works somewhat for docker ps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment