aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ISSUES.markdown2
-rw-r--r--ksh/kshrc.d/keep.ksh152
2 files changed, 154 insertions, 0 deletions
diff --git a/ISSUES.markdown b/ISSUES.markdown
index 0949c0b6..db98183f 100644
--- a/ISSUES.markdown
+++ b/ISSUES.markdown
@@ -16,3 +16,5 @@ Known issues
* dr(1df) is probably more practical in awk
* How come commands I fix with the fc builtin always seem to exit 1 even if
they succeed? Did I do that or is it Bash?
+* mksh(1) when running keep() prints out variables with a "typeset" prefix
+ that seems to mask them when read back in
diff --git a/ksh/kshrc.d/keep.ksh b/ksh/kshrc.d/keep.ksh
new file mode 100644
index 00000000..90fd632f
--- /dev/null
+++ b/ksh/kshrc.d/keep.ksh
@@ -0,0 +1,152 @@
+#
+# keep -- Main function for kshkeep; provided with a list of NAMEs, whether
+# shell functions or variables, writes the current definition of each NAME to a
+# directory $KSHKEEP (defaults to ~/.kshkeep.d) with a .ksh suffix, each of
+# which is reloaded each time this file is called. This allows you to quickly
+# arrange to keep that useful shell function or variable you made inline on
+# subsequent logins.
+#
+# Consider a shell function declared inline with the NAME 'ayy':
+#
+# $ ayy() { printf '%s\n' lmao ; }
+# $ ayy
+# lmao
+# $ keep ayy
+# $ keep
+# ayy
+# $ exit
+#
+# Then, on next login, the function is redefined for you:
+#
+# $ ayy
+# lmao
+#
+# To get rid of it:
+#
+# $ keep -d ayy
+#
+function keep {
+
+ # Name self
+ typeset self
+ self=keep
+
+ # Figure out the directory to which we're reading and writing these scripts
+ typeset kshkeep
+ kshkeep=${KSHKEEP:-"$HOME"/.kshkeep.d}
+ mkdir -p -- "$kshkeep" || return
+
+ # Parse options
+ typeset opt delete
+ typeset OPTERR OPTIND OPTARG
+ while getopts 'dh' opt ; do
+ case $opt in
+
+ # -d given; means delete the keepfiles for the given names
+ d)
+ delete=1
+ ;;
+
+ # -h given; means show help
+ h)
+ cat <<EOF
+$self: Keep variables and functions in shell permanently by writing them to
+named scripts iterated on shell start, in \$KSHKEEP (defaults to
+~/.kshkeep.d).
+
+USAGE:
+ $self
+ List all the current kept variables and functions
+ $self NAME1 [NAME2 ...]
+ Write the current definition for the given NAMEs to keep files
+ $self -d NAME1 [NAME2 ...]
+ Delete the keep files for the given NAMEs
+ $self -h
+ Show this help
+
+EOF
+ return
+ ;;
+
+ # Unknown other option
+ \?)
+ printf 'ksh: %s -%s: invalid option\n' \
+ "$self" "$opt" >&2
+ return 2
+ ;;
+ esac
+ done
+ shift "$((OPTIND-1))"
+
+ # If any arguments left, we must be either keeping or deleting
+ if (($#)) ; then
+
+ # Start keeping count of any errors
+ typeset -i errors
+ errors=0
+
+ # Iterate through the NAMEs given
+ typeset name
+ for name ; do
+
+ # Check NAMEs for validity
+ case $name in
+
+ # NAME must start with letters or an underscore, and contain no
+ # characters besides letters, numbers, or underscores
+ *[!a-zA-Z0-9_]*|[!a-zA-Z_]*)
+ printf 'ksh: %s: %s not a valid NAME\n' \
+ "$self" "$name" >&2
+ ((errors++))
+ ;;
+
+ # NAME is valid, proceed
+ *)
+
+ # If -d was given, delete the keep files for the NAME
+ if ((delete)) ; then
+ rm -- "$kshkeep"/"$name".ksh ||
+ ((errors++))
+
+ # Save a function
+ elif [[ $(whence -v "$name" 2>/dev/null) == *' is a function' ]] ; then
+ typeset -f -- "$name" >"$kshkeep"/"$name".ksh ||
+ ((errors++))
+
+ # Save a variable
+ elif [[ -n "$name" ]] ; then
+ typeset -p -- "$name" >"$kshkeep"/"$name".ksh ||
+ ((errors++))
+ fi
+ ;;
+ esac
+ done
+
+ # Return 1 if we accrued any errors, 0 otherwise
+ return "$((errors > 0))"
+ fi
+
+ # Deleting is an error, since we need at least one argument
+ if ((delete)) ; then
+ printf 'ksh: %s: must specify at least one NAME to delete\n' \
+ "$self" >&2
+ return 2
+ fi
+
+ # Otherwise the user must want us to print all the NAMEs kept
+ (
+ typeset keep
+ for keep in "$kshkeep"/*.ksh ; do
+ [[ -f "$keep" ]] || break
+ keep=${keep##*/}
+ keep=${keep%.ksh}
+ printf '%s\n' "$keep"
+ done
+ )
+}
+
+# Load any existing scripts in kshkeep
+for kshkeep in "${KSHKEEP:-"$HOME"/.kshkeep.d}"/*.ksh ; do
+ [[ -e $kshkeep ]] && source "$kshkeep"
+done
+unset -v kshkeep