You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
5.7 KiB
Bash
183 lines
5.7 KiB
Bash
#!/usr/bin/env bash
|
|
# vim:ts=4:sts=4:sw=4:et
|
|
# shellcheck disable=SC2178,SC2001,SC2128,SC2179
|
|
#
|
|
# Author: Hari Sekhon
|
|
# Date: 2024-07-23 20:43:59 +0300 (Tue, 23 Jul 2024)
|
|
# Ported from Perl version
|
|
# Original Date: 2013-02-11 11:50:00 +0000 (Mon, 11 Feb 2013)
|
|
#
|
|
# https///github.com/HariSekhon/DevOps-Bash-tools
|
|
#
|
|
# License: see accompanying Hari Sekhon LICENSE file
|
|
#
|
|
# If you're using my code you're welcome to connect with me on LinkedIn and optionally send me feedback to help steer this or other code I publish
|
|
#
|
|
# https://www.linkedin.com/in/HariSekhon
|
|
#
|
|
|
|
set -euo pipefail
|
|
[ -n "${DEBUG:-}" ] && set -x
|
|
srcdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# shellcheck disable=SC1090,SC1091
|
|
. "$srcdir/lib/utils.sh"
|
|
|
|
# shellcheck disable=SC2034,SC2154
|
|
usage_description="
|
|
Prints all the command line classpaths of Java processes
|
|
|
|
Optionally filter Java processes by a giving a regex
|
|
"
|
|
|
|
# used by usage() in lib/utils.sh
|
|
# shellcheck disable=SC2034
|
|
usage_args="[<command_process_regex_ere_format>]"
|
|
|
|
help_usage "$@"
|
|
|
|
max_args 1 "$@"
|
|
|
|
# ERE format for [[
|
|
command_regex="${1:-.*}"
|
|
|
|
if ! is_regex "$command_regex"; then
|
|
echo "Invalid command regex supplied: $command_regex"
|
|
exit 1
|
|
fi
|
|
|
|
# use GNU ps on Mac to maintain compatibility
|
|
# doesn't work in subshells
|
|
#if is_mac; then
|
|
# ps(){
|
|
# gps "$@"
|
|
# }
|
|
# export -f ps
|
|
#fi
|
|
|
|
is_jps_output(){
|
|
# JPS output format
|
|
[[ "$1" =~ ^([[:digit:]]+)[[:space:]]+([[:alnum:]]*)$ ]]
|
|
}
|
|
|
|
#replace_classpath_with_token(){
|
|
# sed 's/[[:space:]]-\(cp\|classpath\)[[:space:]=]\+.\+[[:space:]]/ <CLASSPATHS> /' <<< "$1"
|
|
#}
|
|
|
|
show_cli_classpath(){
|
|
local cmd="$1"
|
|
[[ "$cmd" =~ java ]] || return
|
|
args="${cmd#*java }"
|
|
#cmd="$(replace_classpath_with_token "$cmd")"
|
|
echo
|
|
echo "command: $cmd"
|
|
echo
|
|
count=0
|
|
# XXX: will break upon directories in classpath containing a space, but this should be rare on unix systems
|
|
classpaths="$(grep -Eo -- '-(cp|classpath)[=[:space:]]+(.+)[[:space:]]' <<< "$args" || die "Failed to find classpath in args '$args'")"
|
|
classpaths="${classpaths## }"
|
|
classpaths="${classpaths##-cp}"
|
|
classpaths="${classpaths##-classpath}"
|
|
classpaths="${classpaths##=}"
|
|
IFS=':' read -r -a classpaths <<< "$classpaths"
|
|
for classpath in "${classpaths[@]}"; do
|
|
[ -z "$classpath" ] && continue
|
|
echo "classpath: $classpath"
|
|
count=$((count + 1))
|
|
done
|
|
[ $count -gt 0 ] && echo
|
|
echo "$count classpath(s) found"
|
|
echo
|
|
}
|
|
|
|
show_jinfo_classpath(){
|
|
local cmd="$1"
|
|
if is_jps_output "$cmd"; then
|
|
#pid="${cmd%% *}" # first token is pid
|
|
pid="${BASH_REMATCH[1]}"
|
|
# skip Jps itself which may be lingering in the process list from our call before this function
|
|
[ "${BASH_REMATCH[2]:-}" = Jps ] && return
|
|
if [ -z "${BASH_REMATCH[2]:-}" ]; then
|
|
cmd+=" <embedded JVM no classname from JPS output>"
|
|
fi
|
|
echo "JPS: $cmd"
|
|
echo "command: $(ps -f -p "$pid" | tail -n +2 | sed 's/^[[:space:]]*//')"
|
|
echo
|
|
else
|
|
if ! [[ "$cmd" =~ java ]]; then
|
|
# shellcheck disable=SC2028
|
|
echo "skipping $cmd since it doesn't match regex 'java'"
|
|
return
|
|
fi
|
|
#cmd="$(replace_classpath_with_token "$cmd")"
|
|
echo
|
|
echo "command: $cmd"
|
|
if [[ "$cmd" =~ ^[[:space:]]*[[:alnum:]]+[[:space:]]+[[:digit:]]+[[:space:]]+ ]]; then
|
|
echo "ps -ef input detected"
|
|
elif [[ "$cmd" =~ ^[[:space:]]*[[:digit:]]+[[:space:]]+[[:alnum:]]+[[:space:]]+ ]]; then
|
|
echo "ps aux input detected"
|
|
else
|
|
echo "Invalid input to show_jinfo_classpath, expecting '<pid> <classname>' or '<pid> <user> <cmd>' or 'ps -ef' or 'ps aux' input"
|
|
return
|
|
fi
|
|
pid="$(grep -Eo '^[[:digit:]]+' <<< "$cmd")"
|
|
fi
|
|
output="$(jinfo "$pid")"
|
|
found_classpath=0
|
|
while IFS= read -r line; do
|
|
# breaks on this content:
|
|
#
|
|
# /Users/hari/Library/Application Support/JetBrains/IdeaIC2023.3/plugins/sonarlint-intellij/sloop/lib/error_prone_annotations-2.18.0.jar
|
|
#
|
|
#if [[ "$line" =~ error ]]; then
|
|
# echo "jinfo error detected attaching to process id $pid"
|
|
# echo "$line"
|
|
# return
|
|
#fi
|
|
if [[ "$line" =~ ^java.class.path[[:space:]]*=[[:space:]]* ]]; then
|
|
line="${line#*=}"
|
|
line="${line# }"
|
|
count=0
|
|
# jinfo escapes the colon separators with backslashes
|
|
line="$(sed 's/\\:/:/g' <<< "$line")"
|
|
IFS=':' read -r -a classpaths <<< "$line"
|
|
for classpath in "${classpaths[@]}"; do
|
|
[ -z "$classpath" ] && continue
|
|
echo "classpath: $classpath"
|
|
count=$((count + 1))
|
|
done
|
|
[ $count -gt 0 ] && echo
|
|
echo "$count classpath(s) found"
|
|
echo
|
|
found_classpath=1
|
|
break
|
|
fi
|
|
done <<< "$output"
|
|
if [ $found_classpath -eq 0 ]; then
|
|
echo "Failed to find java classpath in output from jinfo!"
|
|
fi
|
|
hr
|
|
}
|
|
|
|
if ! process_list="$(jps 2>/dev/null)"; then
|
|
echo "WARNING: jps failed, perhaps not in \$PATH? (\$PATH = $PATH)" >&2
|
|
echo "WARNING: Falling back to ps command, may be less accurate" >&2
|
|
process_list="$(ps -e -o pid,user,command)"
|
|
fi
|
|
|
|
while IFS= read -r line; do
|
|
log "input: $line"
|
|
if is_jps_output "$line"; then
|
|
if [ -n "$command_regex" ]; then
|
|
if [[ "$line" =~ $command_regex ]]; then
|
|
show_jinfo_classpath "$line"
|
|
fi
|
|
else
|
|
show_jinfo_classpath "$line"
|
|
fi
|
|
elif [[ "$line" =~ java[[:space:]].*$command_regex ]]; then
|
|
#show_jinfo_classpath "$line"
|
|
show_cli_classpath "$line"
|
|
fi
|
|
done <<< "$process_list"
|