Skip to content

Instantly share code, notes, and snippets.

@awwsmm
Last active June 22, 2019 23:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save awwsmm/361bef23c6102acd1f9cc63b58468b60 to your computer and use it in GitHub Desktop.
Save awwsmm/361bef23c6102acd1f9cc63b58468b60 to your computer and use it in GitHub Desktop.
Merge all Java-like "classpath"s in arguments into a single valid classpath, keep other arguments intact
#!/usr/bin/env bash
#-------------------------------------------------------------------------------
#
# array_contains - returns 0 if array contains the specified value, else 1
#
# $1 : term to search for
# $2+ : array to inspect
#
# sources:
# https://stackoverflow.com/a/8574392/2925434
#
#-------------------------------------------------------------------------------
function array_contains {
local match="$1"
shift
for arg; do
[[ "$match" == "$arg" ]] && return 0
done
return 1
}
# usage:
#
# $ if $(array_contains 4 5 7 8); then echo "contains"; else echo "doesn't"; fi
# doesn't
#
# $ if $(array_contains 4 4 5 7 8); then echo "contains"; else echo "doesn't"; fi
# contains
# usage:
#
# $ test[0]=a; test[1]=b; test[2]=c; echo ${test[1]}
# b
#
# $ if $(array_contains c "${test[@]}"); then echo "contains"; else echo "doesn't"; fi
# contains
#
# $ if $(array_contains d "${test[@]}"); then echo "contains"; else echo "doesn't"; fi
# doesn't
#!/usr/bin/env bash
#-------------------------------------------------------------------------------
#
# is_flag - infer whether or not a command-line argument is a flag OR empty
#
# returns 0: arg is flag
# returns 1: arg is not a flag, not empty
# returns 2: arg is empty
#
# sources:
# https://stackoverflow.com/a/10218528/2925434
# https://stackoverflow.com/a/17287097/2925434
#
#-------------------------------------------------------------------------------
function is_flag {
local arg=""
local retval=1
# if is empty, not a flag
if [[ -z "$1" ]]; then
arg="\"\""
retval=2
else
# get first and last characters
local firstchar="${1:0:1}"
local lastchar="${1: -1}"
local short="$1"
# if surrounded by quotes, remove them
if [[ $firstchar == "\"" && $lastchar == "\"" ]] ||
[[ $firstchar == "'" && $lastchar == "'" ]]; then
local lenm2=$((${#1}-2))
short="${1:1:$lenm2}"
fi
# if is empty, not a flag
if [[ -z "$short" ]]; then
arg="\"\"\"\""
retval=2
# if contains spaces, not a flag -- surround with quotes
elif [[ "$short" = *[[:space:]]* ]]; then
arg="\"$short\""
# else, if starts with "-", is a flag -- no quotes
elif [[ "${short:0:1}" == "-" ]]; then
arg="$short"
retval=0
# else, isn't a flag -- surround with quotes
else
arg="\"$short\""
fi
fi
# print arg and return
echo "${arg}"
return $retval
}
# usage:
#
# $ is_flag p # not a flag, surrounded in quotes
# "p"
#
# $ is_flag -p # is a flag, not surrounded in quotes
# -p
#
# $ is_flag "-p" # is a flag, even though surrounded by quotes
# -p
#
# $ is_flag --p # is a flag, any number of - allowed
# --p
#
# $ is_flag "-p a" # not a flag, because quoted and contains spaces
# "-p a"
#
# $ is_flag "-pa" # is a flag, because contains no spaces
# -pa
#
# $ is_flag # no argument given, return empty string
# ""
#
# $ is_flag "" # empty string given, return empty string
# ""
#
# $ is_flag "\"\"" # empty quoted string, return same
# """"
#!/usr/bin/env bash
export JARS_HOME=~/.jenv/jars
# jar locations
export JAVA_JARS_HOME=$JARS_HOME/java
export SCALA_JARS_HOME=$JARS_HOME/scala
# jar lists
export JAVA_JARS_LIST=".:$JAVA_JARS_HOME/\*"
export SCALA_JARS_LIST=".:$JAVA_JARS_HOME/\*:$SCALA_JARS_HOME/\*"
# overrides for jshell, java, etc.
function jshell {
merge_classpath -cp $(eval "echo $JAVA_JARS_LIST") $@ | xargs -o $(whereis jshell)
}
function scala { # replace --class-path with -cp for Scala only
merge_classpath -cp $(eval "echo $SCALA_JARS_LIST") $@ | \
sed 's/--class-path/-cp/' | xargs -o $SCALA_HOME/bin/scala
}
function java {
merge_classpath -cp $(eval "echo $JAVA_JARS_LIST") $@ | xargs -o $JAVA_HOME/bin/java
}
function derby {
java org.apache.derby.tools.ij
}
#!/usr/bin/env bash
#-------------------------------------------------------------------------------
#
# merge_classpath - merge '-cp' '-classpath' and '--class-path' flags and args
#
# sources:
# https://stackoverflow.com/a/1498876/2925434
# https://stackoverflow.com/a/18568726/2925434
# https://stackoverflow.com/a/171041/2925434
# https://stackoverflow.com/a/1405641/2925434
# https://stackoverflow.com/a/17573592/2925434
#
#-------------------------------------------------------------------------------
function merge_classpath {
# loop over all arguments and find any '-cp', etc. flags
flags[0]="-cp"
flags[1]="-classpath"
flags[2]="-class-path"
flags[3]="--cp"
flags[4]="--classpath"
flags[5]="--class-path"
# any argument which immediately follows one of these flags is assumed to be
# another jar file (or list of jar files) to be added to the classpath
# UNLESS the next argument is ALSO a flag (or an empty string) in which case,
# the first ('-cp') flag is ignored
# all other flags and their relationships to each other are kept intact,
# quotes are put around every non-flag argument
local classpath=""
local otherargs=""
for ((ii=1; ii<=$#; ++ii)); do
local jj=$((ii+1))
local this="${!ii}" # current flag / argument
local next="${!jj}" # next flag / argument
# if THIS arg is a -cp-like flag
if array_contains "${this}" "${flags[@]}"; then
# check if the next arg is a flag or empty
is_flag "\"${next}\"" > /dev/null 2>&1
# AND IF the NEXT arg is NOT empty AND NOT a flag, then
if [ $? -eq 1 ]; then
# add to classpath:
# first element added to classpath?
if [[ "$classpath" == "" ]]; then
classpath+="${!jj}"
# prepend all following ones with a ":"
else
classpath+=":${!jj}"
fi
# increment ii to skip next element
((ii++))
# if the next arg is invalid or missing, ignore this -cp-like flag
fi
# if this is some other flag / argument, keep intact
else
otherargs+=" $(is_flag \""${this}"\")"
fi
done
# if classpath is empty, return an error code
if [[ -z "$classpath" ]]; then
echo "${otherargs#?}" # strip leading ' '
return 1
fi
# else, send classpath and other flags and args to stdout and return normally
echo "--class-path \"$classpath\"$otherargs"
return 0
}
# usage:
#
# $ merge_classpath -cp . --class-path /path/to/jars -classpath "some:more:jars"
# --class-path ".:/path/to/jars:some:more:jars"
#
# $ merge_classpath -cp -cp /handles/bad/args --classpath /and/forgotten/ones -cp
# --class-path "/handles/bad/args:/and/forgotten/ones"
#
# $ merge_classpath -cp "retains : spaces" --classpath "in quoted args"
# --class-path "retains : spaces:in quoted args"
#
# $ merge_classpath -f "no classpath flags" "so no --class-path added"
# -f "no classpath flags" "so no --class-path added"
#
# $ merge_classpath "-quoted" "flags have quotes removed"
# -quoted "flags have quotes removed"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment