Skip to content

Instantly share code, notes, and snippets.

@rahogata
Last active June 9, 2023 05:06
Show Gist options
  • Save rahogata/1478cfffd07d2087e53b400079d42332 to your computer and use it in GitHub Desktop.
Save rahogata/1478cfffd07d2087e53b400079d42332 to your computer and use it in GitHub Desktop.
Shell script to edit properties file interactively, add, update, delete, listing properties supported.
#!/bin/sh
# Name: propertyeditor
# Desc: add,update,delete, list properties interactively
# Args: $1 -> property file to edit.
PATH=/bin:/usr/bin:/usr/local/bin
DEFAULTFILE="$HOME/rahogata.properties"
# ignore signals during file operations
#################################
# Name: ignoreSignals
# Desc: ignore major signals
#################################
ignoreSignals() {
trap '' 1 2 3 15
}
#################################
# Name: handleSignals
# Desc: perform operations for
# critical signals
#################################
handleSignals() {
trap "closeEdit;doCleanUp" 1 2 3 15
}
#################################
# Name: dispalyMenu
# Desc: dispaly menu as required
#################################
displayMenu() {
cat << EOH
1. Add Property
2. Update Property
3. Delete Properties
4. Show Properties
5. Exit
EOH
}
closeEdit() {
echo inside closeEdit
mv "$PROPERTYFILE" "$PROPERTYFILE.bak" 2>/dev/null
mv "$UPDATESF" "$PROPERTYFILE" 2>/dev/null
}
doCleanUp() {
echo inside doCleanUp
rm "$UPDATESF.new" 2>/dev/null
}
#################################
# Name: printERROR
# Desc: display error message & exit
# Args: $@ -> all
#################################
printERROR() {
echo "ERROR: $@" >&2
exit 1
}
#################################
# Name: printUSAGE
# Desc: display usage & exit
# Args: $@ -> all
#################################
printUSAGE() {
echo "USAGE: `basename $0` $@" >&2
exit 1
}
#######################################
# Name: _listingHelper
# Desc: helper function to list keys
# with and without number
# Args: $1 -> n for numbering
#######################################
_listingHelper(){
OKEYS=
i=1
if [ "$1" = "-n" ] ; then
OIFS="$IFS"
IFS='
'
for k in `cat -s "$UPDATESF" | tr -d '\015' | grep -v '^ *[!#]\|^ *$'` ; do
OKEYS="$OKEYS
$i. $k"
i=`expr $i + 1`
done
IFS="$OIFS"
unset OIFS
echo "$OKEYS"
else
cat -s "$UPDATESF" | tr -d '\015' | grep -v '^ *[!#]\|^ *$'
fi
}
#######################################
# Name: listKeys
# Desc: retrieve list of updated keys
# Args: $@ -> includes options
#######################################
listKeys() {
_listingHelper $@ | cut -d= -f1
}
######################################
# Name: listValues
# Desc: retrieve list of values only
# Args: $@ -> includes options
######################################
listValues() {
_listingHelper $@ | cut -d= -f2-
}
######################################
# Name: getKey
# Desc: retrieve key from $UPDATESF
# Args: $1 -> key index
######################################
getKey() {
echo "`listKeys | sed "$1!d" | tr -d ' '`"
}
######################################
# name: getvalue
# desc: retrieve value from $updatesf
# args: $1 -> key index
######################################
getvalue() {
echo "`listValues | sed "$1!d" | tr -d ' '`"
}
######################################
# Name: getComment
# Desc: retrieve comment line from
# $UPDATESF
# Args: $1 -> key name
######################################
getComment() {
echo "`awk '
{
if ( $0 ~ pattern ) {
print comments;
}
else if ( $0 !~ /^ *[!#]/ ) {
comments="";
}
else {
comments=comments"\n"$0;
}
}' pattern="^ *$1" "$UPDATESF" | grep -v '^ *$'`"
}
#######################################
# Name: promptRESPONSE
# Desc: display prompt and get response
# Args: $1 -> prompt
# $2 -> old value
# $3 -> true if blank allowed
#######################################
promptRESPONSE() {
DEF_VAL="$2"
RESPONSE=
if [ -z "$3" ] || [ "$3" = "false" ] ; then
while [ -z "$RESPONSE" ]
do
printf "$1:[$2] "
read RESPONSE
done
else
printf "$1:[$2] "
read RESPONSE
fi
RESPONSE="${RESPONSE:-"$DEF_VAL"}"
unset DEF_VAL
}
########################################
# Name: promptYESNO
# Desc: ask yes/no question
# Args: $1 -> prompt
# $2 -> default answer
########################################
promptYESNO() {
YESNO=
printf "$1(y/n):[$2] "
read YESNO
case "$YESNO" in
[yY]|[yY][eE][sS]) YESNO="y" ;;
[nN]|[nN][oO]) YESNO="n" ;;
*) YESNO="$2" ;;
esac
}
###############################################
# Name: hasProperty
# Desc: check if property already exist
# Args: $1 -> key
# $2 -> properties list variable or file
###############################################
hasProperty() {
_ECHO="echo"
if [ -f "$2" ] ; then
_ECHO="cat"
fi
if [ "`$_ECHO "$2" | grep "^$1"`" = "" ] ; then
return 1
fi
}
###########################################
# Name: addProperty
# Desc: add property to list of properties
# interactively
# Args: $1 -> key
# $2 -> value
# $3 -> comment
###########################################
addProperty() {
ignoreSignals
printf "#%s\n%s=%s\n" "$3" "$1" "$2" >> "$UPDATESF"
handleSignals
}
##########################################
# Name: updateProperty
# Desc: update value of property
# Args: $1 -> key line number
# $2 -> value
##########################################
updateProperty() {
ignoreSignals
PKEY="`getKey $1`"
if [ ! -z "$PKEY" ] ; then
sed "s/^ *${PKEY}.*$/${PKEY}="${PVAL}"/" "$UPDATESF" > "$UPDATESF.new" 2>/dev/null
mv "$UPDATESF.new" "$UPDATESF"
fi
handleSignals
}
##########################################
# Name: deleteProperty
# Desc: delete a property
# Args: $1 -> key serial no.
##########################################
deleteProperty() {
ignoreSignals
PKEY="`getKey $1`"
PCOMMENT="`getComment "$PKEY"`"
if [ ! -z "$PKEY" ] ; then
grep -v "^ *$PKEY" "$UPDATESF" | grep -v "$PCOMMENT" > "$UPDATESF.new" 2>/dev/null
mv "$UPDATESF.new" "$UPDATESF"
fi
handleSignals
}
# main()
handleSignals
# first print usage for -h option
if [ $# -eq 1 ] && [ "$1" = "-h" ] ; then
printUSAGE "[options] [file]"
fi
# shift args all but last one
shift `expr $# - 1` >/dev/null 2>&1
# set variable for file
PROPERTYFILE="${1:-$DEFAULTFILE}"
# check file existence.
if [ ! -f "$PROPERTYFILE" ] ; then
printERROR "Property file $PROPERTYFILE does not exists or not a file."
fi
# act on a copy of the file
UPDATESF="pupdates.$$"
cp "$PROPERTYFILE" "$UPDATESF"
while :
do
echo
displayMenu
# ask choice
promptRESPONSE "Choose" 5 true
case "$RESPONSE" in
# add property for choice 1
1)
while :
do
promptRESPONSE "Key"
PKEY="$RESPONSE"
promptRESPONSE "Value" "" true
PVAL="$RESPONSE"
promptRESPONSE "Comment" "" true
PCOMMENT="$RESPONSE"
if hasProperty "$PKEY" "$UPDATESF" ; then
echo "Property already exists."
read
break
fi
addProperty "$PKEY" "$PVAL" "$PCOMMENT"
promptYESNO "Continue adding property" n
if [ "$YESNO" = "n" ] ; then
break
fi
done
;;
2)
while :
do
listKeys -n
promptRESPONSE "Choose" "" true
KEYIDX="$RESPONSE"
if [ -z "$KEYIDX" ] ; then
break
fi
promptRESPONSE "Value" "`getvalue $KEYIDX`" true
PVAL="$RESPONSE"
updateProperty "$KEYIDX" "$PVAL"
echo "Property updated successfully."
promptYESNO "Update some more" n
if [ "$YESNO" = n ] ; then
break
fi
done
;;
3) while :
do
listKeys -n
promptRESPONSE "Choose" "" true
if [ -z "$RESPONSE" ] ; then
break
fi
promptYESNO "Delete selected?" n
if [ "$YESNO" = n ] ; then
break
fi
deleteProperty $RESPONSE
echo "Property deleted successfully."
promptYESNO "Continue deleting?" n
if [ "$YESNO" = n ] ; then
break
fi
done
;;
4)
echo
awk -F= '!/^ *[!#]|^ *$/ {
i = i + 1;
printf "%d. %s",i, $1;
$1="->";
print $0;
}' "$UPDATESF"
promptYESNO "Press Enter to continue" y
;;
*) if [ "$RESPONSE" -eq 5 ] ; then
break
fi
;;
esac
done
closeEdit
doCleanUp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment