-
-
Save Masterxilo/29ac0df083827bbd45a7c8ddcf3936d7 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# This script adds a program/script/command called 'permfunction' to you PATH | |
# permfunction allows you to write system-wide, on-PATH instantly available, persisted scripts, i.e. improved shell functions/aliases/abbreviations/short programs. | |
# | |
# TODO also persist these functions as gists for the user | |
# inspired by | |
# https://askubuntu.com/questions/1414/how-to-create-a-permanent-alias | |
# https://askubuntu.com/a/80290/521770 | |
# | |
# installation/update to latest version for current user (this takes precedence over global version, if your PATH is set up as usually): | |
# | |
# curl -s https://gist.githubusercontent.com/Masterxilo/29ac0df083827bbd45a7c8ddcf3936d7/raw/permfunction | bash - ; hash -d permfunction &> /dev/null || true | |
# | |
# installation/update of global version for all users (depending on your PATH only this might work out of the box): | |
# | |
# curl -s https://gist.githubusercontent.com/Masterxilo/29ac0df083827bbd45a7c8ddcf3936d7/raw/permfunction | sudo -E bash - ; hash -d permfunction &> /dev/null || true | |
# | |
# This last way of installing is required if you want to use sudo permfunction. | |
# | |
# uninstall: | |
# rm ~/bin/permfunction | |
# sudo rm /usr/bin/permfunction | |
# Note: Installation of the very latest version should be done with a hardlink to the current version /raw/.../functionname instead, because http caching | |
# in the gist server makes the /raw/functionname route not always reflect the latest update | |
set -e | |
# note that -e only exits immediately if top level error occus - except pipelines (see below) and sequences (unconditional continuation), expressions are evaluated to completion | |
set -o pipefail | |
installdir="/usr/bin" | |
! [ -w "$installdir" ] && { installdir="$HOME/bin" ; } | |
mkdir "$installdir" &> /dev/null || true | |
file="$installdir/permfunction" | |
[ -f "$file" ] && { echo >&2 "warning: $file exists, overwriting" ; } | |
echo "installing permfunction at $file..." ; | |
which permfunction &> /dev/null && ! [ "`which permfunction`" == "$file" ] && { echo >&2 "error: permfunction is already installed elsewhere at `which permfunction`. Prefer to have one up-to-date installation to avoid version confusion." ; exit 1 ; } | |
# -------- permfunction source code ----------- | |
cat > "$file" <<'EOF' | |
#!/bin/bash | |
set -e | |
set -o pipefail | |
[ "$1" == "--redefine" ] && { shift ; redefine=true ; } | |
[ "$1" == "--file" ] && { shift ; file=true ; } | |
name="$1" | |
if [ -z "$redefine" ] ; then | |
which "$name" &>/dev/null && { echo "error: command with name $name exists at `which "$name"`. use --redefine to overwrite" ; exit 1 ; } || true # refuse to overwrite/take precedence over existing commands to avoid confusion! | |
fi | |
shift || true # shift fails if there are no variables! | |
code=$(echo "$@") # code is not just $2, but all remaining args, space separated | |
[ ! -z "$file" ] && { code=$(cat "$code") ; } | |
FD_NUMBER_STDIN=0 # this is a system constant in linux | |
if [ -z "$code" ] && [[ -t $FD_NUMBER_STDIN ]] ; then | |
echo >&2 "code is not defined and STDIN is a tty which is not allowed. use 'cat - | permfunction $name' if you want a simple editor. or use 'echo code | permfunction $name'"; | |
echo "" | |
# will display usage below: | |
else | |
[ -z "$code" ] && { | |
code="$(cat /dev/stdin)"; | |
} | |
fi | |
( [ "$name" == "-help" ] || [ "$name" == "-?" ] || [ "$name" == "--?" ] || [ "$name" == "--help" ] || [ -z "$name" ] || [ -z "$code" ] ) && { cat >&2 <<'USAGEEOF' | |
permfunction allows you to write system-wide, on-PATH instantly available, persisted scripts, i.e. improved shell functions/aliases/abbreviations/short programs. | |
usage: [sudo] permfunction [--redefine] name code | |
[sudo] permfunction [--redefine] name code more-code even-more-code | |
[sudo] permfunction [--redefine] name <<'EOF' | |
code | |
EOF | |
[sudo] permfunction [--redefine] name < file_containing_code | |
-command generating code on stdout- | [sudo] permfunction [--redefine] name | |
[sudo] permfunction [--redefine] --file name file_containing_code | |
where stdin cannot be a tty (we don't want to implement any line/terminal editing in this tool). | |
usage examples: | |
permfunction cls "clear" | |
after this, cls does the same as clear or ctrl+l in any open terminal (with the same PATH) | |
sudo permfunction cls "clear" | |
same, but install for all users | |
permfunction sayhi 'echo Hello $1' | |
after this, "sayhi World" prints "Hello World". Note that we cannot let the shell expand $1!!! | |
permfunction dosomething ' | |
echo "this script does" | |
echo "something with $1" | |
echo "which is so complex that it needs this many lines!!!" | |
' | |
after this, try 'dosomething "your shell"', and check out 'cat `which dosomething`' | |
USAGEEOF | |
exit 1 ; } | |
re="[[:space:]]+" | |
if [[ "$name" =~ $re ]]; then | |
echo >&2 "usage: permfunction [--redefine] name code" ; | |
echo >&2 "error: name may not contain spaces, was '$name'" ; | |
exit 1 ; | |
fi | |
installdir="/usr/bin" # system install. requires sudo to write | |
! [ -w "$installdir" ] && { installdir="$HOME/bin" ; } | |
mkdir "$installdir" &> /dev/null || true | |
file="$installdir/$name" | |
[ -f "$file" ] && [ -z $redefine ] && { | |
echo >&2 "error: $file exists. Use --redefine to force overwriting" ; | |
[ -w ] && echo >&2 "or use rm $file to delete the existing command manually first"; | |
! [ -w ] && echo >&2 "or use sudo rm $file to delete the existing command manually first"; | |
exit 1 ; | |
} | |
[ -f "$file" ] && ! [ -z $redefine ] && { echo >&2 "warning: $file exists. Redefining." ; } | |
echo "$code" > "$file" | |
chmod +x "$file" | |
echo "installed $name to $file" | |
echo "-------------- code listing 'cat $file' ---------------" | |
cat "$file" | |
echo "-------------- code listing end ---------------" | |
! [ "`which $name`" == "$file" ] && { echo >&2 """ | |
error: Installation in PATH failed | |
which $name | |
returns | |
`which $name` | |
instead of expected | |
$file | |
Probably '$installdir' is not in your PATH or another program of the same name is taking precedence. If you used [sudo] permfunction, try to use with/without sudo instead. | |
""" ; exit 1 ; } | |
[ "`which $name`" == "$file" ] && { echo "successfully installed $name in PATH, you can now use it" ; } | |
hash -d $name &> /dev/null || true # no idea if this helps something/escapes the scope of this script | |
EOF | |
chmod +x $file | |
name="permfunction" | |
echo "installed $name to $file" | |
! [ "`which $name`" == "$file" ] && { echo >&2 """ | |
error: Installation in PATH failed | |
which $name | |
returns | |
`which $name` | |
instead of expected | |
$file | |
Probably '$installdir' is not in your PATH or another program of the same name is taking precedence. If you used [sudo] permfunction, try to use with/without sudo instead. | |
"""; exit 1 ; } | |
[ "`which $name`" == "$file" ] && { echo "successfully installed $name in PATH, you can now use it" ; } | |
hash -d permfunction &> /dev/null || true # no idea if this helps something/escapes the scope of this script | |
hash -d permfunction
to stop permfunction from being searched in the wrong place after reinstallling.
TODO make this persist the functions to a repository
TODO make all functions/scripts this creates self-updating
tested working on ubuntu & WSL (windows subsystem for linux) ubuntu
however, on WSL the PATH is polluted with windows stuff, so only the sudo variant worked - the personal ~/bin dir appears not to be in the PATH.
Here's a command I recently defined (adapted from https://stackoverflow.com/questions/12498304/using-bash-to-display-a-progress-working-indicator https://stackoverflow.com/a/50699733/524504):
permfunction --redefine spinner <<'EOF'
#!/usr/bin/env bash
show_spinner()
{
local -r pid="${1}"
local -r delay='0.05'
local spinstr='\|/-'
local temp
while ps a | awk '{print $1}' | grep -q "${pid}"; do
temp="${spinstr#?}"
printf " [%c] " "${spinstr}"
spinstr=${temp}${spinstr%"${temp}"}
sleep "${delay}"
printf "\b\b\b\b\b\b"
done
printf " \b\b\b\b"
}
("$@") &
show_spinner "$!"
EOF
usage:
spinner sleep 5
(known problem: the cursor jumps around and blinks to draw this spinner)
Recommended aliases:
- define
- pfunction
- persistent_function
- persist
definition using:
permfunction --redefine palias $'name=$1; shift; permfunction $name "$@"\' "$@"\''
# then
palias define permfunction
palias pfunction permfunction
palias persistent_function permfunction
palias persist permfunction
palias persistent_alias palias
nice command: recursive touch/mkdir -p
palias mkdirp 'mkdir -p'
permfunction touchp 'mkdir -p "$(dirname "$1")" && touch "$1" ;'
palias touch2 touchp
https://askubuntu.com/questions/800845/create-file-and-its-parent-directory
touchp test/about/me
find test
tree test
touchp src/main/java/hello/Application.java
for
https://spring.io/guides/gs/testing-web/
it would be cool if I could know what the current revision's url is when installing... maybe using the etag ...