readded udpated scripts directory

This commit is contained in:
tomit4 2022-06-09 12:59:03 -07:00
parent cd053a412a
commit f3117c81d9
84 changed files with 3210 additions and 0 deletions

9
scripts/README.md Normal file
View file

@ -0,0 +1,9 @@
<h4>My Notes on Introduction to Shell Scripting</h4>
This repository includes my notes and exercises regarding Bash Shell Scripting.
It currently includes some exercises from the book, Wicked Cool Shell Scripts, but because these are a little too advanced for me at this time, I am currently making my way through the following website's introductory lessons regarding Bash Scripting:
https://guide.bash.academy/expansions
Hopefully these notes/lessons will serve me well as I continue to attempt to understand the basics of Linux and the Bash shell.

3
scripts/acrl Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
article_md "https://$1" --format=html | hxnormalize -e | grep -v -e '^$' | pygmentize -l html

43
scripts/array_methods.sh Executable file
View file

@ -0,0 +1,43 @@
#!/bin/bash
# There are many interesting array methods within bash, this file simply contains some examples of a few of them.
# Deleting an entire array or single element of an array.
#array=(a b 1 "c")
#echo ${array[@]}
# prints
# a b 1 c
#unset array
# deletes entire array
#echo ${array[@]}
# prints nothing
# Create an Array from a string, similar to the JavaScript split(' ') method.
#stringVar="Apple Orange Banana Mango"
#arrayVar=(${stringVar// / })
#echo ${arrayVar[@]}
# prints
# Apple Orange Banana Mango
# Note that the above example is a classic. It uses a space as a delimiter in an otherwise simple regex search and delineate function. The first parameter passed after the double forward slash syntax // , is a simple empty space, which is what it will look for to establish the array, the second white space I'm not exactly sure why, but it is necessary for it to process the command properly.
# Here's the same example using a plus sign as a delimiter:
#stringVar="Apple+Orange+Banana+Mango"
#arrayVar=(${stringVar//+/ })
#echo ${arrayVar[@]}
# prints
# Apple Orange Banana Mango
# Accessing the last element of an array. Pretty simple, just use -1 as the index number:
#fruits=(banana kiwi pineapple)
#echo ${fruits[-1]}
# prints
# pinepalle

119
scripts/associative_arrays.sh Executable file
View file

@ -0,0 +1,119 @@
#!/bin/bash
# In Section 12.6 of Bash Notes for Professionals, an introduction to Associative Arrays is given, in which the author expands upon the Bash Syntax of arrays becoming similar to Objects in traditional programming languages (or dictionaries in Python).
# Essentially we can define an index name within an Array. This essentially makes them akin to Objects.
# Declare an associative arrays
declare -A aa
aa[hello]=world
aa[ab]=cd
aa["key with space"]="hello world"
# You can also declare an array more simply by writing it all in one line like so:
#aa=([hello]=world [ab]=cd ["key with space"]="hello world")
#echo ${aa[hello]}
# prints
# world
#echo ${aa[ab]}
# prints
# cd
# Note that from trying to use this as an actualy command it doesn't work, there probably is a way to cd from a file like this, but there was no apparent answer found online.
#echo ${aa["key with space"]}
# prints
# "hello world"
# You can access, and therefore echo, a list of the associative array keys like so:
# Note that it is the exclamation point here that accesses the keys, without it we access the values.
#echo "${!aa[@]}"
# prints
# key with space ab hello
#echo "${aa[@]}"
# prints
# hello world cd world
# Iterating over associative array keys and values
#for key in "${!aa[@]}"; do
#echo "Key: ${key}"
#echo "Value: ${aa[$key]}"
#done
# prints
#Key: key with space
#Value: hello world
#Key: ab
#Value: cd
#Key: hello
#Value: world
# Associative Arrays are, in essence, objects, though I don't know if they can have their own methods at this time (bash has surprised me thus far, but I would be very surprised if it had this functionality). Nevertheless, let's establish a format for declaring a large Associative Array, like so (section 13.1 of the GoalKicker Bash book).
declare -A assoc_array=([key_string]=values \
[one]="something" \
[two]="another thing" \
[three]='mind the blanks' \
["four"]="count the blanks of this key later!" \
[IMPORTANT]='SPACES DO ADD UP!!!' \
[1]='there are no integers!' \
[info]="to avoid history expansion" \
[info2]="quote exclamation mark with single quotes" \
)
#echo # just a blank line
#echo now here are the values of assoc_array:
#echo ${assoc_array[@]}
# This is nice, but unfortunately not that useful, as while it does print the entirity of the associative array, it does so on one line, and only includes the values
#echo # just a blank line
#echo this is better:
#declare -p assoc_array # -p == print
# This will still print all in one line, but includes the entire array, key/value pairs are printed.
# Now let's access just the keys:
#echo # just a blank line
#echo accessing the keys:
#echo the keys in the assoc_array are ${!assoc_array[*]}
# Now let's loop through the array and print it out nicely
#echo # just a blank line
#echo printing the key/value pairs nicely:
#for key in "${!assoc_array[@]}"; do
#printf "key: \"%s\"\nvalue: \"%s\"\n\n" "$key" "${assoc_array[$key]}"
#done
# Note that associative arrays and arrays of integers do not work the same way when attempting to access their values for arithmetic. It is important to make this distinction when attempting to perform operations on their values.
#echo # just a blank line
#echo demonstrating difference between associative arrays, and integer arrays:
#echo this works: \${assoc_array[\$i]}: ${assoc_array[$i]}
#echo this does NOT work: \${assoc_array[i]}: ${assoc_array[i]}
# let's use this in an example:
i=1
echo ${assoc_array[\$i]}: ${assoc_array[$i]}
# Doesn't quite work yet, see chapter 13.1 of Bash Notes for Professionals from GoalKicker.com to continue

69
scripts/bestcompress Executable file
View file

@ -0,0 +1,69 @@
#!/bin/bash
# ERROR: /bin/bash -w is invalid option is the error message here. Unable to find answer to problem at this time.
# Keeping this file for learning purposes.
# bestcompress--Given a file, tries compressing it with all the available
# compression tools and keeps the compressed file that's smallest,
# reporting the result to the user. If -a isn't specified, bestcompress
# skips compressed files in the input stream.
Z="compress" gz="gzip" bz="bzip2"
Zout="/tmp/bestcompress.$$.Z"
gzout="/tmp/bestcompress.$$.gz"
bzout="/tmp/bestcompress.$$.bz"
skipcompressed=1
if [ "$1" = "-a" ] ; then
skipcompressed=0 ; shift
fi
if [ $# -eq 0 ] ; then
echo "Usage: $0 [-a] file or files to optimally compress" >&2
exit 1
fi
trap "/bin/rm -f $Zout $gzout $bzout" EXIT
for name in "$@"
do
if [ ! -f "$name" ] ; then
echo "$0: file $name not found. Skipped." >&2
continue
fi
if [ "$(echo $name | egrep '(\.Z$|\.gz$|\.bz2$)')" != "" ] ; then
if [ $skipcompressed -eq 1 ] ; then
echo "Skipped file ${name}: It's already compressed."
continue
else
echo "Warning: Trying to double-compress $name"
fi
fi
# Try compressing all three files in parallel.
$Z < "$name" > $Zout &
$gz < "$name" > $gzout &
$bz < "$name" > $bzout &
wait # Wait until all compressions are done.
# Figure out which compressed best.
smallest="$(ls -l "$name" $Zout $gzout $bzout | \parallel
awk '{print $5"="NR}' | sort -n | cut -d= -f2 | head -1)"
case "$smallest" in
1 ) echo "No space savings by compressing $name. Left as is."
;;
2 ) echo Best compression is with compress. File renamed ${name}.Zout
mv $Zout "${name}.Z" ; rm -f "$name"
;;
3 ) echo Best compression is with gzip. File renamed ${name}.gz
mv $gzout "${name}.gz" ; rm -f "$name"
;;
4 ) echo Best compression is with bzip2. File renamed ${name}.bz2
mv $bzout "${name}.bz2" ; rm -f "$name"
esac
done
exit 0

125
scripts/bgit Executable file
View file

@ -0,0 +1,125 @@
#!/bin/bash
# For styling/colorizing output
txtbld=$(tput bold)
txtblue=${txtbld}$(tput setaf 4)
txtgreen=${txtbld}$(tput setaf 2)
txtred=${txtbld}$(tput setaf 1)
txtyellow=${txtbld}$(tput setaf 3)
txtwhite=${txtbld}$(tput setaf 7)
# Intro Prompt
echo "${txtblue}bgit: a handy shell script for automating the standard git process"
# Reset output style
tput bold & tput setaf 7
# counts the number of repos
numrepos=$(git remote | wc -l)
# If there are no git repositories in this directory...
if [ $numrepos -eq 0 ] ; then
echo "${txtred}no git repositories in this directory...exiting bgit${txtwhite}"
exit 1
fi
# creates a list of repos and puts them in an array
repoarray=($(git remote))
# Grabs all new files
newfiles=$(git status --short | grep '??' | awk '{print $2}' | tr '\n' ' ')
# Grabs all modified files
modified=$(git status --short | grep M | awk '{print $2}' | tr '\n' ' ')
# Grabs all deleted files
deleted=$(git status --short | grep D | awk '{print $2}' | tr '\n' ' ')
# Reports what is staged for commit
# If there is anything to commit...
if [[ ! -z $newfiles || ! -z $modified || ! -z $deleted ]] ; then
# Let the user know what is staged for commit
echo "${txtwhite}The following files are staged for commit:"
# Otherwise, if there isn't anything to commit...
else
# Let the user know that everything is up to date
echo "${txtred}everything up-to-date...exiting bgit${txtwhite}"
# and exit the program
exit 0
fi
# Let the user know what is staged for commit
if [[ $newfiles ]]; then
echo "${txtgreen}ADDED: ${txtgreen}$newfiles"
fi
if [[ $modified ]]; then
echo "${txtblue}MODIFIED: ${txtblue}$modified"
fi
if [[ $deleted ]]; then
echo "${txtred}DELETED: ${txtred}$deleted"
fi
while [ true ]
do
# Prompts user if they'd like to commit the changes
read -r -p "${txtwhite}commit changes?(y/n): ${txtyellow}" change
# If the user chooses to commit the changes...
if [[ $change == "y" || $change == "yes" ]] ; then
# Grabs commit message
while [ true ]
do
# Prompts the user to input their commit message
read -r -p "${txtwhite}commit message: ${txtyellow}" message
cmessage=("$message")
# if the user inputted a commit message...
if [ -n "$message" ] ; then
# then break out of the while loop and continue with the commit...
break
# if the user did NOT input a commit message...
else
# tell the user to do so or to quit
echo "${txtred}commit message is empty, please write a commit message"
echo "${txtred}or type 'CTRL+C' to quit${txtwhite}"
fi
done
# Reset output style
tput bold & tput setaf 7
# adds the modified and new files (suppresses message anyways if no files are to be committed)
if [[ $newfiles || $modified ]] ; then
git config advice.addEmptyPathspec false
git add $modified $newfiles ;
fi
# commits the user's message (multi-word supported)
git commit -m "$cmessage" ;
# pushes the commit to each repository
for ((i = 0; i < $numrepos; i++)) ; do
git push ${repoarray[i]} ;
done
exit 0
# If the user chooses to not the commit the changes ...
elif [[ $change == "n" || $change == "no" ]] ; then
# Reset output style
tput bold & tput setaf 7
# Report the git status
git status --short
# And let the user know no changes were committed
echo "${txtred}no changes committed"
exit 0
# If the user chooses to quit...
elif [[ $change == "q" || $change == "quit" ]] ; then
exit 0
# If the user continues to just press enter...
else
echo "${txtred}please enter y or n or type 'q' or 'quit' or 'CTRL+C' to quit${txtwhite}"
fi
done

35
scripts/bmap Executable file
View file

@ -0,0 +1,35 @@
#!/bin/bash
# bmap runs nmap on an domain name address by first looking up the ip address using dnslookup and then passing that ip address to nmap through proxychains/tor
if [ $# -eq 0 ] ; then
echo "No arguments provided."
echo "Type 'bmap -h' for help"
exit 1
fi
while getopts "ph" opt; do
case $opt in
p)
ipaddress=$(dnslookup ${3} 149.112.112.112 | grep IN | grep -v \; | awk -F '\t' '{print $5}' | head -n 1)
port=$2
proxychains nmap -Pn -T4 -n -sT -sV -v --open -p $port $ipaddress
exit 0
;;
h)
echo -e "\e[1mUsage: bmap <url> (no 'https://' necessary)\e[0m"
echo -e "\e[1mUsage: bmap -p <portnumber> <url> (no 'https://' necessary)\e[0m"
exit 0
;;
\?)
printf "Invalid flag option: $1 \nType 'jscurl -h' for help.\n" >&2
exit 1
;;
esac
done
if [ $OPTIND -eq 1 ] ; then
ipaddress=$(dnslookup ${1} 149.112.112.112 | grep IN | grep -v \; | awk -F '\t' '{print $5}' | head -n 1)
proxychains nmap -Pn -T4 -n -sT -sV -v --open $ipaddress
exit 0
fi

50
scripts/calc Executable file
View file

@ -0,0 +1,50 @@
#!/bin/bash
# calc--A command line calculator that acts as a frontend to bc
# Establishing the amount of decimal places bc will expect, in this case the default 2
scale=2
# Establishing a show_help() function that will display a message to the user if they invoke calc, and then type help or ?
show_help()
{
cat << EOF
In addition to standard math functions, calc also supports:
a % b remainder of a/b
a ^ b exponential: a raised to the b power
s(x) sine of x, x in radians
c(x) cosine of x, x in radians
a(x) arctangent of x, in radians
l(x) natural log of x
e(x) exponential log of raising e to the x
j(n,x) Bessel function of intenger order n of x
scale N show N fractional digits (default = 2)
EOF
}
# This is a very simple script, here, as long as the arguments passed to calc are greater than 0, calc simply executes the scriptbc script we wrote earlier.
if [ $# -gt 0 ] ; then
exec scriptbc "$@"
fi
# Otherwise if no arguments are passed to calc, it opens up a prompt that displays this message
echo "Calc--a simple calculator. Enter 'help' for help, 'quit' to quit."
# the read command is what keeps the prompt open, here the while loop invokes the read command,
# which awaits bash command, and then takes the newly created $args variable...
while read command args
do
case $command # if the $command variable is...
in
quit|exit) exit 0 ;; # quit/exit causes an exit of the program with a success/ok status...
help|\?) show_help ;; # help/? brings up the help message above
scale) scale=$args ;; # if scale is invoked, you can change the default value of the $scale variable
*) scriptbc -p $scale "$command" "$args" ;; # otherwise any other commands will simply invoke the scriptbc script
esac
/bin/echo -n "calc>" # afterwards which you will be returned to the calc> prompt
done
echo "" # after invoking calc with arguments, a blank line is printed.
exit 0 # and an success/ok status is passed upon exit.

11
scripts/case_example.sh Executable file
View file

@ -0,0 +1,11 @@
#!/bin/bash
echo -n "Enter the name of an animal: "
read ANIMAL
echo -n "The $ANIMAL has "
case $ANIMAL in
horse | dog | cat) echo -n "four";;
man | kangaroo ) echo -n "two";;
*) echo -n "an unkonwn number of";;
esac
echo " legs."

74
scripts/cgrep Executable file
View file

@ -0,0 +1,74 @@
#!/bin/bash
# cgrep--grep with context display and highlighted pattern matches
# Usage Example:
# cgrep -c 1 Introduction bash_copy.txt
context=0
esc="^["
boldon="${esc}[1m" boldoff="${esc}[22m"
sedscript="/tmp/cgrep.sed.$$"
tempout="/tmp/cgrep.$$"
function showMatches
{
matches=0
echo "s/$pattern/${boldon}$pattern${boldoff}/g" > $sedscript
for lineno in $(grep -n "$pattern" $1 | cut -d: -f1)
do
if [ $context -gt 0 ] ; then
prev="$(( $lineno - $context ))"
if [ $prev -lt 1 ] ; then
# This results in "invalid usage of line address 0."
prev="1"
fi
next="$(( $lineno + $context ))"
if [ $matches -gt 0 ] ; then
echo "${prev}i\\" >> $sedscript
echo "----" >> $sedscript
fi
echo "${prev},${next}p" >> $sedscript
else
echo "${lineno}p" >> $sedscript
fi
matches="$(( $matches + 1 ))"
done
if [ $matches -gt 0 ] ; then
sed -n -f $sedscript $1 | uniq | more
fi
}
trap "$(which rm) -f $tempout $sedscript" EXIT
if [ -z "$1" ] ; then
echo "Usage: $0 [-c X] pattern {filename}" >&22m
exit 0
fi
if [ "$1" = "-c" ] ; then
context="$2"
shift; shift
elif [ "$(echo $1|cut -c1-2)" = "-c" ] ; then
context="$(echo $1 | cut -c3-)"
shift
fi
pattern="$1"; shift
if [ $# -gt 0 ] ; then
for filename ; do
echo "----- $filename -----"
showMatches $filename
done
else
cat - > $tempout # Save stream to a temp file.
showMatches $tempout
fi
exit 0

67
scripts/convertatemp Executable file
View file

@ -0,0 +1,67 @@
#!/bin/bash
# convertatemp--Temperature conversion script that lets the user enter
# a temperature in Farenheit, Celsius, or Kelvin and receive the
# equivalent temperature in the other two units as the output
# Usage Examples:
# convertatemp 212 # default behavior, farenheit conversion
# convertatemp 100C # celsius conversion
# convertatemp 100K # kelvin conversion
# just a test of debugging mode using set (comment out later)
#set -n
if [ $# -eq 0 ] ; then # if no arguments are passed
# then redirect from EOF (End of FILE) the string until another EOF caps off the string.
# essentially, this just prints a message to the user about how to use the script.
cat << EOF >&2
Usage: $0 temperature[F|C|K]
where the suffix:
F indicates input is in Fahrenheit (default)
C indicates input is in Celsius
K indicates input is in Kelvin
EOF
exit 1 # and exit with an error status
fi
# the variable, $unit is assigned the echoed first argument, which is piped to sed, which takes a regular expression that expects any amount of digits
# the '-' means to include anything but the following, which essentially means unit becomes just the letter passed (f,c,k)
# this is then piped to tr (transform), which takes strings and converts them, in this case all lowercase is converted to uppercase
unit="$(echo $1|sed -e 's/[-[:digit:]]*//g' | tr '[:lower:]' '[:upper:]' )"
# the $temp variable is assigned the first parameter's digits only
temp="$(echo $1|sed -e 's/[^-[:digit:]]*//g')"
case ${unit:=F} # if the unit's final character is F...
in
F ) # Farenheit to Celsius formula: Tc = (F - 32) / 1.8
farn="$temp"
cels="$(echo "scale=2;($farn - 32) / 1.8" | bc)"
kelv="$(echo "scale=2;$cels + 273.15" | bc)"
;;
C ) # Celsius to Fahrenheit formula: Tf = (9/5)*Tc+32
cels="$temp"
kelv="$(echo "scale=2;$cels + 273.15" | bc)"
farn="$(echo "scale=2;(1.8 * $cels) + 32" | bc)"
;;
K ) # Celsius = Kelvin - 273.15, then use Celsius -> Fahrenheit formula
kelv="$temp"
cels="$(echo "scale=2;($kelv - 32) / 1.8" | bc)"
farn="$(echo "scale=2;(1.8 * $cels) + 32" | bc)"
;;
*) # otherwise, if F,C, or K are not passed, then...
echo "Given temperature unit is not supported"
exit 1 # and exit with an error status.
esac
#Finally, we simply print back the results
echo "Fahrenheit = $farn"
echo "Celsius = $cels"
echo "Kelvin = $kelv"
# and exit with a success/ok status
exit 0

34
scripts/dmconf Executable file
View file

@ -0,0 +1,34 @@
#!/bin/sh
DMENU="dmenu -i -l 20 -p"
DMEDITOR="st -e nvim"
declare -a confedit_list=(
"alias - $HOME/.aliases"
"bash - $HOME/.bashrc"
"zsh - $HOME/.zshrc"
"btop - $HOME/.config/btop/btop.conf"
"st - $HOME/.config/st/config.h"
"bspwm - $HOME/.config/bspwm/bspwmrc"
"sxhkd - $HOME/.config/sxhkd/sxhkdrc"
"picom - $HOME/.config/picom/picom.conf"
"i3 - $HOME/.config/i3/config"
"kitty - $HOME/.config/kitty/kitty.conf"
"nvim - $HOME/.config/nvim/lua/config.lua"
"ranger - $HOME/.config/ranger/rifle.conf"
"tuir - $HOME/.config/tuir/tuir.cfg"
)
if [[ "${confedit_list[@]}" ]]; then
choice=$(printf '%s\n' "${confedit_list[@]}" | $DMENU 'Edit config:')
else
echo "Program terminated." && exit 1
fi
if [[ "$choice" == "quit" ]]; then
echo "Program terminated." && exit 1
elif [ "$choice" ]; then
cfg=$(printf '%s\n' "${choice}" | awk '{print $NF}')
$DMEDITOR $cfg
else
echo "Program terminated." && exit 1
fi

22
scripts/dmwiki Executable file
View file

@ -0,0 +1,22 @@
#!/bin/sh
wikidir="/usr/share/doc/arch-wiki/html/en/"
wikidocs="$(find ${wikidir} -iname "*.html")"
browser="links"
term="st"
main() {
choice=$(printf '%s\n' "${wikidocs[@]}" | \
dmenu -l 20 -p 'Arch Wiki Docs: ') || exit 1
if [ "$choice" ]; then
$term -e $browser "$choice"
else
echo "Program terminated." && exit 0
fi
}
main

7
scripts/dnsl Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
ipaddress=$(dnslookup ${1} 149.112.112.112 | grep IN | grep -v \; | awk -F '\t' '{print $5}' | head -n 1)
source /home/brian/.api_key.sh
curl -s -H "Accept: application/json" "http://api.ipapi.com/$ipaddress/?access_key=$api_key" | jq

55
scripts/formatdir Executable file
View file

@ -0,0 +1,55 @@
#!/bin/bash
# formatdir--Outputs a directory listing in a friendly and useful formatdir
# Note that you need to ensure "scriptbc" (Script #9) is in your current path
# because it's invoked within the script more than once.
scriptbc=$(which scriptbc)
# Function to format sizes in KB to KB, MB, or GB for more readable output
readablesize()
{
if [ $1 -ge 1048576 ] ; then
echo "$($scriptbc -p 2 $1 / 1048576)GB"
elif [ $1 -ge 1024 ] ; then
echo "$($scriptbc -p 2 $1 / 1024)MB"
else
echo "${1}KB"
fi
}
################
## MAIN CODE
if [ $# -gt 1 ] ; then
echo "Usage: $0 [dirname]" >&2
exit 1
elif [ $# -eq 1 ] ; then # Specified a directory other than the current one?
cd "$@" # Then let's change to that one.
if [ $? -ne 0 ] ; then # Or quit if the directory doesn't exist.
exit 1
fi
fi
for file in *
do
if [ -d "$file" ] ; then
size=$(ls "$file" | wc -l | sed 's/[^[:digit:]]//g')
if [ $size -eq 1 ] ; then
echo "$file ($size entry)|"
else
echo "$file ($size entries)|"
fi
else
size="$(ls -sk "$file" | awk '{print $1}')"
echo "$file ($(readablesize $size))"
fi
done | \
sed 's/ /^^^/g' | \
xargs -n 2
sed 's/\^\^\^/ /g' | \
awk -F\| '{ printf "%-39s %-39s\n", $1, $2 }'
exit 0

61
scripts/functions.sh Executable file
View file

@ -0,0 +1,61 @@
#!/bin/bash
# Just like in other programming languages, bash has functions. Functions in bash do look somewhat similar to functions in other programming languages, with some caveats. Note here how in this funciton called greet(), there is a reference to a parameter called $1, which is also preceded by the variable name by the term 'local', which probably refers to name being a local variable. It is then assigned the value of $1, which is the first parameter to be passed after calling the function, in this case, it called "John Doe" after the funciton invocation greet. That argument is then passed as "$1", which is then assigned to the local variable name, which then is echoed back in a string, with "Hello, " preceding it.
#greet() {
#local name="$1"
#echo "Hello, $name"
#}
#greet "John Doe"
# prints - Hello, John Doe
# Here we see a general reference to all parameters, which is referenced using the @ symbol. #foo() {
#echo "$@"
#}
#foo 1 2 3
# prints - 1 2 3
# You can also create a default value of the arguments like so:
#bar() {
#local val=${1:-25}
#echo "$val"
#}
#bar # prints 25 by default
#bar 30 # prints 30
# You can actually reference other bash scripts' functions in other files or even in the shell itself by using the source keyword, try this from the terminal:
# source functions.sh
# greet "John Doe"
# prints - Hello, John Doe
# From the bash.pdf, we have found that the use of the 'local' reserved word, we can declare local variables within functions, which as the document states, can be very useful when used within other functions,
# This is demonstrated below:
func1()
{
local var='A string local to func1'
func2
}
func2()
{
echo "In func2, var = $var"
}
var="A string within the global scope"
func1
# prints
# In func2, var = A string local to func1
# note that even though we declared var again within the global scope, when we printed the value of var in func1(), it returned us the local variable instead, if we had not declared var prepended by the local reserved word,
# it would still have printed the same, because $var is reassigned a different value when func1OP is invoked. That said, if we then echo $var within the global scope, we should get the global value:
echo $var
# prints
# "A string within the global scope"

68
scripts/getopts_check.sh Executable file
View file

@ -0,0 +1,68 @@
#!/bin/bash
# This file was copied from Kris Occhipinti's Shell Scripting playlist on youtube.
# You can find the video at: https://www.youtube.com/watch?v=5O4SLIDSMqg
# It introduces the basics of the getopts command, which in this particular script, sets up flags to be used, which when invoked
# will produce a different result/behavior depending on which flags are chosen.
# Here we create a funciton called main(), which is invoked at the end of this script.
function main(){
# Firstly, the main() function invokes the check() function defined below. It is invoked with all passed arguments, defined by the $@ syntax.
check $@
# If the $m argument is true, then the main() function will echo back "'m' has been chosen."
if [ $m ]
then
echo "'m' has been chosen."
fi
}
# And here we define our check() function, which uses the getopts command...
function check(){
# Firstly we define some local variables (local to this function), OPTIND, opt, and i are all declared here, but not defined.
# NOTE that OPTIND represents the index of the last option argument processed by the getopts builtin.
# NOTE that OPTARG represents the value of the last option argument processed by the getopts builtin.
local OPTIND opt i
# while loop that uses getopts to look at each flag defined after the getopts command, in this case "cmni"
# NOTE the colons prepending and appending the cmni flags, the first colon is to expand the variables so that any one of them can be invoked, not necessarily one after the other, the appending colon is to tell bash that we also SHOULD expect arguments after these flags.
# Whatever flags are passed are contained within the local variable, $opt,
while getopts ":cmni:" opt; do
# a case statement that checks what is in the $opt variable and procedes with different processes/commands depending on what was chosen.
case $opt in
# if the -i flag was chosen, we echo back the choice, as well as set the global variable $input to equal the global variable $OPTARG
i) echo "You chose 'i'";input="$OPTARG";;
# if -c flag is chosen, we simply echo back the choice.
c) echo "'c' is a good option";;
# if the -m flag is chosen, the $m global variable is set to true, which is then checked in our main() function
m) m=true;;
# if the -n flag is chosen, teh n_func() funciton is invoked, which is defined below and simply echos back the choice.
n) n_func ;;
# if any other flag is chosen (i.e. a flag that was not defined by getopts above), then we invoke the help() function and exit with an error code of 1, you can think of this as the default statment in Javascript's switch/case statements
\?) help;exit 1 ;;
esac
done
# OPTIND is the index number of the current argument, and is usually defaulted to 1. Here we shift [n] to change the current positional parameters (the arguments) to the left by n times, in this case we are telling bash to essentially look at the next flag in the $OPTIND parameter
shift $((OPTIND -1))
# Here very simply we are looking at the local $input variable and seeing if it is empty, if not, we simply output the value of $input
if [ "$input" = "" ]
then
echo "No input file"
else
echo "Input is $input"
fi
}
# The rest is relatively straight forward.
function help(){
echo "Help. I need somebody"
echo "Help. Not just anybody"
}
function n_func(){
echo "this is the n_func"
}
main $@

3
scripts/hcrl Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
torsocks curl -s https://{$1} | hxnormalize -e | grep -v -e '^$' | pygmentize -l html

52
scripts/inpath Executable file
View file

@ -0,0 +1,52 @@
#!/bin/bash
# inpath--Verifies that a specified program is either valid as is
# or can be found in the PATH directory list
in_path()
{
# Given a command and the PATH, tries to find the command. Returns 0 if
# found and executable; 1 if not. Note tha this temporarily modifies
# the IFS (internal field separator) but restores it upon completion.
cmd=$1 ourpath=$2 result=1
oldIFS=$IFS IFS=":"
for directory in $ourpath
do
if [ -x $directory/$cmd ] ; then
result=0 # If we're here, we found the command.
fi
done
IFS=$oldIFS
return $result
}
checkForCmdInPath()
{
var=$1
if [ "$var" != "" ] ; then
if [ "${var:0:1}" = "/" ] ; then
if [ ! -x $var ] ; then
return 1
fi
elif ! in_path $var "$PATH" ; then
return 2
fi
fi
}
#if [ $# -ne 1 ]; then
#echo "Usage: $0 command" >&2
#exit 1
#fi
#checkForCmdInPath "$1"
#case $? in
#0 ) echo "$1 found in PATH" ;;
#1 ) echo "$1 not found or not executable" ;;
#2 ) echo "$1 not found in PATH" ;;
#esac
#exit 0

4
scripts/intro Executable file
View file

@ -0,0 +1,4 @@
#!/bin/bash
echo "Hello World"
echo $(which neqn)
cat $(which neqn)

125
scripts/jscurl Executable file
View file

@ -0,0 +1,125 @@
#!/bin/bash
# Greatly shortens JSON curl statements.
# NOTE: This should be rewritten to use jo and jq, as this does something very similar.
# curl will be coming with --json flag in version 7.82.0 in March of 2022, this will likely make this far less verbose.
if [ $# -eq 0 ] ; then
echo "No arguments provided."
echo "Type 'jscurl -h' for help."
exit 1
fi
body=${3}
helptag="-help"
archivedir="$HOME/.recycle-bin"
# Show help page
function helpmessage()
{
echo -e "\e[1mUsage: jscurl <url> (no 'https://' necessary)\e[0m"
echo ""
echo -e "\e[1mExample: jscurl icanhazdadjoke.com\e[0m"
echo ""
echo -e "\e[1mDescription: jscurl is a simple extension of curl that reads/writes json/html, shortening\n\t the length of the curl command when dealing explicitly with json/html output.\e[0m"
echo ""
echo -e "\e[1mOptions and arguments:\e[0m"
echo ""
echo -e "\e[1mlocalhost only:\e[0m"
echo -e "\e[1mjscurl -g 3000/db\t\t\t\t\t\t\t\t get request json\e[0m"
echo -e "\e[1mjscurl -p 3000/db '{"key": "value"}'\t\t\t\t\t\t post request json\e[0m"
echo -e "\e[1mjscurl -d 3000/db '{"deleted_key": "deleted_value"}'\t\t\t delete request json\e[0m"
echo -e "\e[1mjscurl -u 3000/db '{"updated_key": "updated_value", "previous_key": "previous_value"}'\tpatch request json\e[0m"
echo ""
echo -e "\e[1mjson/html:\e[0m"
echo -e "\e[1mjscurl <url> (no 'https://' necessary)\t\t\t\t\t\t show json page\e[0m"
echo -e "\e[1mjscurl -m <url> (no 'https://' necessary)\t\t\t\t\t show html page\e[0m" echo -e "\e[1mjscurl -w <url> <filename> (no 'https://' or '.html' necessary)\t write html file to ~/.recycle-bin\e[0m"
echo -e "\e[1mjscurl -j <url> <filename> (no 'https://' or '.json' necessary)\t write json file to ~/.recycle-bin\e[0m"
echo -e "\e[1mjscurl -h/--help\t\t\t\t\t\t\t\t show help page\e[0m"
}
while getopts "mwjgpudh${helptag}" opt; do
case $opt in
m)
curl -s https://{$2} | hxnormalize -e | pygmentize -l html
exit 0
;;
w)
curl -s https://{$2} -o $3.html &&
prettier --loglevel silent -w $3.html
if [ ! -d $archivedir ] ; then
mkdir $archivedir
fi
if [ ! -d "${archivedir}/html" ] ; then
mkdir "${archivedir}/html"
fi
mv $3.html "${archivedir}/html"
exit 0
;;
j)
curl -s -H "Accept: application/json" https://{$2} | cat > $3.json &&
prettier --loglevel silent -w $3.json
if [ ! -d $archivedir ] ; then
mkdir $archivedir
fi
if [ ! -d "${archivedir}/json" ] ; then
mkdir "${archivedir}/json"
fi
mv $3.json "${archivedir}/json"
exit 0
;;
g)
http_req="GET"
port="http://localhost:${2}"
;;
p)
http_req="POST"
port="http://localhost:${2}"
;;
u)
http_req="PUT"
port="http://localhost:${2}"
;;
d)
http_req="DELETE"
port="http://localhost:${2}"
;;
h | helptag)
helpmessage
;;
\?)
printf "Invalid flag option: $1 \nType 'jscurl -h' for help.\n" >&2
exit 1
;;
esac
done
if [ $OPTIND -eq 1 ] ; then
port="https://${1}"
curl -s -H "Accept: application/json" $port | jq
exit 0
fi
function jscurl() {
if [[ $http_req = "GET" ]]; then
curl -s -X "$http_req" "$port" | jq
exit 0
else
curl -s -X "$http_req" "$port" -H "Content-Type: application/json" -d "$body" &&
curl -s -X "GET" "$port" | jq
exit 0
fi
}
jscurl
# examples:
# jscurl icanhazdadjoke.com
# jscurl -g 3000/db
# jscurl -p 3000/db '{"listArray": "some"}'

50
scripts/jscurl_with_notes Executable file
View file

@ -0,0 +1,50 @@
#!/bin/bash
# get this funciton to create a curl command that takes in 3 parameters,
# the HTTP REQUEST TYPE, the site to be curled, and the JSON data to be passed.Simple JSON POST request:
#curl -X POST http://host:3000/maria_database -H "Content-Type: application/json" -d '{"task": "DONE IN CURL"}'
#Simple JSON DELETE request:
#curl -X DELETE http://host:3000/maria_database -H "Content-Type: application/json" -d '{"deletedItem": "DONE IN CURL"}'
#Simple JSON PUT request:
#curl -X PUT http://host:3000/maria_database -H "Content-Type: application/json" -d '{"updated": "WE DID THIS IN CURL AGAIN", "previous": "DONE IN CURL"}'
#echo "$1"
#echo "$2"
#echo "$3"
http_req=${1^^}
port="http://localhost:${2}"
#json=" '{\"${3}\": [\"${4}"\""]}'"
#echo \'{\"${3}\": [\"${4}\"]}\'
#echo $http_req
#echo $json
#echo $port
#echo "$2"
#echo "$3"
#echo "$4"
#curl -X "{$http_req}" "{$site}" -H "Content-Type: application/json" -d "{$json}"
#curl -X " {$http_req} " "{$port}" -H "Content-Type: application/json" -d "$3"
#curl -X POST http://localhost:3000/maria_database -H "Content-Type: application/json" -d '{"listArray": ["do it forever"]}'
# Only one that works currently:
#curl -X "$http_req" "$port" -H "Content-Type: application/json" -d '{"listArray": ["do it again forever"]}'
if [[ $http_req = "GET" ]]; then
curl "$http_req" "$2"
else
curl -X "$http_req" "$port" -H "Content-Type: application/json" -d "$3"
fi
#curl -X "$1" "$2" -H "Content-Type: application/json" -d "$3"
#### FEATURES I'D LIKE TO IMPLEMENT ####
# format JSON to be human readable upon output (possibly using prettier)
# perhaps create a second program for non localhost related curl commands that still use JSON ( will require another variable, which as is made apparent above, is difficult for you to work with at your current skill level with bash programming)

132
scripts/loops.sh Executable file
View file

@ -0,0 +1,132 @@
#!/bin/bash
# A standard for loop can be done similar to python for in range:
#arr=(a b c d e f)
#for i in "${arr[@]}" ; do
#echo "$i"
#done
# A more classical approach that stems from C:
#arr=(g h i j k)
#for ((i=0; i<${#arr[@]}; i++)) ; do
#echo "${arr[$i]}"
#done
# A while loop:
#arr=(q r s t u v)
#i=0
#while (( $i < ${#arr[@]} )) ; do
#echo "${arr[$i]}"
#((i++))
#done
# Iterating over an array of numbers
#for i in {1..10}; do # expands to "1 2 3 4 5 6 7 8 9 10"
#echo $i
#done
# Continue and break statements within for loops:
# This seems like it would just print a once and that'd be that, like the example below which prints g once. But this loop produces a five times over, which is unexpected...
#arr=(a b c d e f)
#for i in ${arr[@]} ; do
#if [[ ${arr[i]} = a ]] ; then
#echo "${arr[i]}"
#continue
#else
#break
#fi
#done
# This is what I would encourage my future self to use, as it is more readable and reflects how a traditional for loop looks with an if and else and continue and break statements in other programming languages.
# Note the i<${#arr[@]}; parameter in the middle there, this is very similar to the array.length parameter in JavaScript or len in Python (admitttedly it looks a little strange). Just keep in mind that the hashtag # denotes length
#arr=(g h i j k l)
#for (( i=0; i<${#arr[@]}; i++ )) ; do
#if [[ ${arr[i]} = g ]] ; then
#echo "${arr[$i]}" # just returns g...
#continue # and then continues through the loop...
#else
#break # but once it hits h, it breaks out of the loop
#fi
#done
# While loops
#i=0
#while [ $i -lt 5 ]
#do
#echo "i is currently $i"
#i=$[$i+1] # Note the lack of spaces around the brackets.
#done # ends the loos
# prints:
# i is currently 0
# i is currently 1
# i is currently 2
# i is currently 3
# i is currently 4
# C style for loop, this is somewhat similar to the for loop we created above which counts over the array, the following is more straight forward as the amount of iterations is hard coded, but demonstrates the flexibility with which a for loop can be implemented in bash.
#for (( i = 0; i < 10; i++ ))
#do
#echo "The iteration number is $i"
#done
# prints:
# The iteration number is 0
# The iteration number is 1
# The iteration number is 2
# The iteration number is 3
# The iteration number is 4
# The iteration number is 5
# The iteration number is 6
# The iteration number is 7
# The iteration number is 8
# The iteration number is 9
# We can also process multiple variables inside C-style for loop:
# Note the use of commas instead of semicolons here, the semicolons help the for function delineate between parameters, while the commas can establish multiple similar "sub"-parameters within the for loop, this is potentially powerful, as it can define multiple variables and parameters within the for loop prior to it's initialization (with the 'do' syntax)
#for (( i = 0, j = 0; i < 10; i++, j = i * i ))
#do
#echo "The square of $i is equal to $j"
#done
# prints
# The square of 0 is equal to 0
# The square of 1 is equal to 1
# The square of 2 is equal to 4
# The square of 3 is equal to 9
# The square of 4 is equal to 16
# The square of 5 is equal to 25
# The square of 6 is equal to 36
# The square of 7 is equal to 49
# The square of 8 is equal to 64
# The square of 9 is equal to 81
# Until Loop
# This is the first time I have encountered an until loop. It checks for a truthy statement, and when it reaches it, it ends. You can thank of this as a for/if statement or a while statment with a built in break statement.
#i=5
#until [[ i -eq 10 ]]; do #Checks if i=10
#echo "i=$i" #Prints the value of i
#i=$((i+1)) #Increments i by 1
#done
# prints
# i=5
# i=6
# i=7
# i=8
# i=9

8
scripts/makelist Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
# makelist creates a list of current packages, removes the second field (version numbers), and replaces all the new lines with spaces and then writes it to a file called my_packages.txt, you can more or less copy and paste this list into pacman -S to re-download all your files, useful if you need to start from scratch. Needs a script eventually to query aur_packages directory for packages downloaded directly from AUR and not Artix repositories.
pacman -Q | awk '!($2="")' | tr '\n' ' ' >> my_packages.txt
# can be used in conjunction with xargs to reinstall all packages:
# cat my_packages.txt | sudo xargs pacman -S

8
scripts/makelist_laptop Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
# makelist creates a list of current packages, removes the second field (version numbers), and replaces all the new lines with spaces and then writes it to a file called my_packages.txt, you can more or less copy and paste this list into pacman -S to re-download all your files, useful if you need to start from scratch. Needs a script eventually to query aur_packages directory for packages downloaded directly from AUR and not Artix repositories.
pacman -Q | awk '!($2="")' | tr '\n' ' ' >> my_packages_laptop.txt
# can be used in conjunction with xargs to reinstall all packages:
# cat my_packages_laptop.txt | sudo xargs pacman -S

3
scripts/mcrl Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
torsocks curl -sL https://${1} | pandoc -f html -t markdown | grep -v -e '^$' | grep -v -e ":::" | pygmentize -l markdown

28
scripts/newcal Executable file
View file

@ -0,0 +1,28 @@
#!/bin/sh
# cal: nicer interface to usr/bin/cal
case $# in
0) set 'date'; m=$2; y=$6 ;; # no args; use today
1) m=$1; set 'date'; y=$6 ;; # 1 arg; use this year
2) m=$1; y=$2 ;; # 2 args; month and year
esac
case $m in
jan*|Jan*) m=1 ;;
feb*|Feb*) m=2 ;;
mar*|Mar*) m=3 ;;
apr*|Apr*) m=4 ;;
may*|May*) m=5 ;;
jun*|Jun*) m=6 ;;
jul*|Jul*) m=7 ;;
aug*|Aug*) m=8 ;;
sep*|Sep*) m=9 ;;
oct*|Oct*) m=10 ;;
nov*|Nov*) m=11 ;;
dec*|Dec*) m=12 ;;
[1-9]|10|11|12) ;; # numeric month
*) y=$m; m="" ;; # plain year
esac
/usr/bin/cal $m $y # run the real one

54
scripts/newrm Executable file
View file

@ -0,0 +1,54 @@
#!/bin/bash
# newrm--A replacement for the existing rm command.
# This script provides a rudimentary unremove capability by creating and
# utilizing a new directory within the user's home directory. It can handle
# directories of content as well as individual files. If the user specifies
# the -f flag, files are removed and NOT archived.
# Big Important Warning: You'll want a cron job or something similar to keep
# the trash directories tamed. Otherwise, nothing will ever actually
# be deleted from the system, and you'll run out of disk space!
archivedir="$HOME/.recycle-bin"
realrm="$(which rm)"
copy="$(which cp) -R"
if [ $# -eq 0 ] ; then # Let 'rm' output the usage error.
exec $realrm # Our shell is replaced by /bin/rm
fi
# Parse all options looking for '-f'
flags=""
while getopts "dfiPRrvW" opt
do
case $opt in
f ) exec $realrm "$@" ;; # exec lets us exit this script directly.
* ) flags="$flags -$opt" ;; # Other flags are for rm, not us.
esac
done
shift $(( $OPTIND - 1 ))
# BEGIN MAIN SCRIPT
# =================
if [ ! -d $archivedir ] ; then
if [ ! -w $HOME ] ; then
echo "$0 failed: can't create $archivedir in $HOME " >&2
exit 1
fi
mkdir $archivedir
chmod 700 $archivedir # A little bit of privacy, please
fi
for arg
do
newname="$archivedir/$(date "+%S.%M.%H.%m").$(basename "$arg")"
if [ -f "$arg" -o -d "$arg" ] ; then
$copy "$arg" "$newname"
fi
done
exec $realrm $flags "$@" # Our shell is replaced by realrm.

46
scripts/newrm_with_notes Executable file
View file

@ -0,0 +1,46 @@
#!/bin/bash
# Here we establish some essential variables to the program.
archivedir="$HOME/.recycle-bin" # we simply refer to a directory .recycle-bin that will house copies of all our deleted files.
realrm="$(which rm)" # a variable that allows us to reference the binary rm program
copy="$(which cp) -R" # and the same for the cp command
if [ $# -eq 0 ] ; then # if there are no arguments (i.e. the length of the array of arguments is equal to zero)
exec $realrm # then simply execute the rm command
fi
# Parse all options looking for '-f'
flags="" # a variable that will obviously hold our flags, note that it is expecting a string and not an array
# the getopts command allows us to create a series of flags, note the syntax here as it will be useful in multiple programs.
while getopts "dfiPRrvW" opt do # note the $opt variable is created here, very much like in a for in loop.
case $opt in # in case the $opt variable is in the string above, (the "dfiPRrvW" string which indicates the various kinds of flags)
f ) exec $realrm "$@" ;; # execute the rm command followed by all variables/flags that follow it
* ) flags="$flags -$opt" ;; # otherwise all other flags passed are contained in the flags variable
esac
done
shift $(( $OPTIND - 1 )) # this syntax is necessary as it is part of the getopts syntax, which then shifts through the option index ($OPTIND) by one,
# essentially checking the next flag
# BEGIN MAIN SCRIPT
# =================
if [ ! -d $archivedir ] ; then # if the .recycle-bin directory doesn't exist...
if [ ! -w $HOME ] ; then # and if the $HOME directory is NOT writable
echo "$0 failed: can't create $archivedir in $HOME " >&2 # echo the message and write it to standard output
exit 1 # and exit with an error status
fi
mkdir $archivedir # otherwise, write the .recycle-bin directory
chmod 700 $archivedir # and change the permissions so only the $USER can read/write/execute the directory
fi
for arg # as simple as it gets for a for statement... for every argument passed (the filename(s))...
do
newname="$archivedir/$(date "+%S.%M.%H.%m").$(basename "$arg")" # in the variable, newname, write within the .recycle-bin directory the filename with a timestamp prepended to it
if [ -f "$arg" -o -d "$arg" ] ; then # if the passed filename is a regular file and exists and/or the file's optname is true and/or is a directory...
$copy "$arg" "$newname" # use the cp command to copy the arguments passed to newrm with the newname variable (i.e. copy the passed file(s) to the recycle-bin directory as the same filename with a timestampe prepended to it)
fi
done
exec $realrm $flags "$@" # execute the rm command with the passed flags ("dfiPRrvW") and all arguments(file(s))

6
scripts/node_script.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/node
console.log('THIS IS FROM NODE DIRECTLY!')
//#!/bin/bash
//node >>> 'console.log("HELLO FROM NODE")'

55
scripts/nodejs_spawn.js Normal file
View file

@ -0,0 +1,55 @@
//This file is just to demonstrate how nodejs can, like python, execute bash commands, here we have it execute the ls command on our Documents folder.This utilizes node's native 'util' modules, as well as child_process, spawn. This is one way of doing it. Further below we can also use the more versatile exec() method.
/*
const util = require('util'),
spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/home/brian/Documents'])
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data)
})
ls.stderr.on('data', function (data) {
console.log('stderr ' + data)
})
ls.on('exit', function (code) {
console.log('child process exited with code ' + code)
})
*/
// Outputs:
//stdout: total 12K
//drwxr - xr - x 5 brian brian 4.0K Dec 12 23: 47 Code
//drwxr - xr - x 17 brian brian 4.0K Dec 12 23: 26 notes
//drwxr - xr - x 2 brian brian 4.0K Dec 12 23: 47 programming_books
//child process exited with code 0
let util = require('util'),
exec = require('child_process').exec,
child
child = exec('ls -lh /home/brian/Documents',
function (error, stdout, stderr) {
console.log('stdout: ' + stdout)
console.log('stderr: ' + stderr)
if (error !== null) {
console.log('exec error: ' + error)
}
// Splits the output's lines into separate strings to be iterated over
//const lsArr = stdout.split(`\n`)
//console.log(lsArr)
}
)
//Outputs:
//stdout: total 12K
//drwxr - xr - x 5 brian brian 4.0K Dec 12 23: 47 Code
//drwxr - xr - x 17 brian brian 4.0K Dec 12 23: 26 notes
//drwxr - xr - x 2 brian brian 4.0K Dec 12 23: 47 programming_books
//stderr:

47
scripts/normdate Executable file
View file

@ -0,0 +1,47 @@
#!/bin/bash
# normdate--Normalizes month field in date specification to three letters,
# first letter capitalized. A helper function for Script #7, valid-date.
# Exits with 0 if no error.
monthNumToName()
{
# Sets the 'month' variable to the approrpriate value.
case $1 in
1 ) month="Jan" ;; 2 ) month="Feb" ;;
3 ) month="Mar" ;; 4 ) month="Apr" ;;
5 ) month="May" ;; 6 ) month="Jun" ;;
7 ) month="Jul" ;; 8 ) month="Aug" ;;
9 ) month="Sep" ;; 10 ) month="Oct" ;;
11 ) month="Nov" ;; 12 ) month="Dec" ;;
* ) echo "$0: Unknown month value $1" >&2
exit 1
esac
return 0
}
# BEGIN MAIN SCRIPT--DELETE OR COMMENT OUT EVERYTHING BELOW THIS LINE IF
# YOU WANT TO INCLUDE THIS IN OTHER SCRIPTS.
# =================
# Input validation
if [ $# -ne 3 ] ; then
echo "Usage: $0 month day year" > &2
echo "Formats are August 3 1962 and 8 3 1962" >&2
exit 1
fi
if [ $3 -le 99 ] ; then
echo "$0: expected 4-digit year value." >&2
exit 1
fi
# Is the month input format a number?
if [ -z $(echo $1|sed 's/[[:digit:]]//g') ] ; then
monthNumToName $1
else
# Normalize to first 3 letters, first upper- and then lowercase.
month="$(echo $1|cut -c1|tr '[:lower:]' '[:upper:]')"
month="$month$(echo $1|cut -c2-3 | tr '[:upper:]' '[:lower:]')"
fi
echo $month $2 $3
exit 0

5
scripts/ocrl Executable file
View file

@ -0,0 +1,5 @@
#!/bin/bash
source /home/brian/.api_key.sh
curl -s -H "Accept: application/json" "http://www.omdbapi.com/?apikey=$omdbapi_key&t=$1" | jq

28
scripts/overwrite Executable file
View file

@ -0,0 +1,28 @@
#!/bin/sh
# overwrite: copy standard input to output after EOF
# final version
opath=$PATH
PATH=/bin:/usr/bin
case $# in
0|1) echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
esac
file=$1; shift # recall that shift moves all arguments one position to the left
new=/tmp/overwr1.$$; old=/tmp/overwr2.$$
trap 'rm -f $new $old; exit 1' 1 2 15 # clean up files
if PATH=$opath "$@" >$new
then
cp $file $old # save original file
trap '' 1 2 15 # we are committed; ignore signals
cp $new $file
else
echo "overwrite: $1 failed, $file unchnaged" 1>$2
exit 1
fi
rm -f $new $old
# USAGE: ow.sh notice sed 's/UNIX/UNIX(TM)/g' notice

27
scripts/ow_v1.sh Executable file
View file

@ -0,0 +1,27 @@
#!/bin/sh
# overwrite: copy standard intput to output after EOF
# version 1. BUG here
PATH=/bin:/usr/bin
case $# in
1) ;;
*) echo `Usage: overwrite file` 1>&2; exit 2
esac
new=/tmp/overwr.$$
trap `rm -f $new; exit 1` 1 2 15
cat >$new # collect the input
cp $new $1 # overwrite the input file
rm -f $new
# this file is used solely as a first example of how to think about
# programming in the shell language.
# cp is used instead of mv so the permissions and owner of the output file aren'the
# changed if it already exist.
# Appealingly simple as this version is, it has a fatal flaw: if the user types
# DEL during the cp, the original input file will be ruined. We must prevent and
# interrupt from stopping the overwriting of the input file. (see ow_v2.sh)

33
scripts/ow_v2.sh Executable file
View file

@ -0,0 +1,33 @@
#!/bin/sh
# overwrite: copy standard input to output after EOF
# version 2. BUG here too
PATH=/bin:/usr/bin
case $# in
1) ;;
*) echo 'Usage: overwrite file' 1>&2; exit 2
esac
new=/tmp/overwr1.$$
old=/tmp/overwr2.$$
trap 'rm -f $new $old; exit 1' 1 2 15
cat >$new # collect the input
cp $1 $old # save original file
trap '' 1 2 15 # we are committed; ignore signals
cp $new $1
rm -f $new $old
# solving the original problem we had in ow_v1.sh:
# If a DEL happens berfore the original file is touched, then the temporary files
# are removed and the file is left alone. After the backup is made, signals are ignored
# so the last cp won't be interrupted -- once the cp starts, overwrite is commited to
# changing the original file.
# However, this implementation is still flawed (see pg 154 of The Unix Programming Environment).
# If the program providing input to overwrite gets an error, its output will be empty and overwrite will dutifully and reliably destroy the argument file. (see ow.sh for final version)

BIN
scripts/parallel/0.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/1.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/10.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/2.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/3.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/4.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/5.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/6.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/7.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/8.html.gz Normal file

Binary file not shown.

BIN
scripts/parallel/9.html.gz Normal file

Binary file not shown.

View file

@ -0,0 +1,18 @@
NOTE: You will need to download GNU parallel for this (doas pacman -S parallel)
This is just some notes regarding what's in here. The html files were created using a simple for loop:
for (( i=0; i<=10; i++ )); do
touch $i.html
done
Then in the command line, I copied a command from the bash.pdf book I'm reading in order to better understand GNU parallel, a command line program that allows for parallel processes to be executed (similar to xargs):
find . -type f -name '*.html' -print | parallel gzip
This will use the find command within the current directory, of a the type file, with the name all files that end in .html, and then send to standard output the results via the -print flag, afterwards which those
results are piped to GNU parallel which then asynchronously processes them through gzip (and thusly, compresses all .html files).
Note that GNU parallel is a powerful command line tool, you can execute a series of commands in sequence by reading them from a file and then passing them through parallel using the -j flag:
parallel -j 10 < file

View file

@ -0,0 +1,8 @@
#!/bin/bash
# Note you will need to install both parallel and traceroute to use this (doas pacman -S parallel traceroute)
{
echo foss.org.my ;
echo debian.org ;
echo freenetproject.org ;
#} | parallel traceroute
} | parallel -k traceroute # makes sure that the output of parallel is displayed in the order that the arguments passed were given (i.e. foss.org.my results are displayed first)

8
scripts/permissions.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
if [[ "$(id -u)" -ne 0 ]]; then
echo "[ERROR] You must run this script as root!"
exit 0
else
echo "You are root!"
fi

3
scripts/ph Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
# chromium --incognito https://www.pornhub.com/video/search?search="${1}" &
librewolf https://www.pornhub.com/video/search?search="${1}" &

28
scripts/play_with_getopts.sh Executable file
View file

@ -0,0 +1,28 @@
#!/bin/bash
# Very essentially getopts allows us to create commands with flags
# Usually getopts is used in conjunction with a while loop, which takes in a series of flag strings which are expected,
# it then defines a variable (in this case $opt) which then is used within a case statement to define its behavior
while getopts "ab" opt; do
case $opt in
a)
echo "-a was triggered!" >&2
# after we have sent the echo to standard output, we shift the remaining arguments by one so that we can reference them later
shift 1
# we can of course exit with a success status if we don't want to continue with operations after the -a flag is invoked
#exit 0
;;
b)
echo "-b was triggered also!" >&2
shift 1
#exit 0
;;
\?)
echo "Invalid option: -$OPTARG" >&2
#exit 1
;;
esac
done
# this is why we used shift earlier, so to utilize it later in our script after the while loop is done checking our various flags.
echo $1

8
scripts/print_args.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
# This simple script demonstrates the use of the special iterator "$@", which will take in an infinite number of arugments passed and print them out.
# This could prove useful when you don't know how many arguments you are going to have, such as when iterating over a series of files.
for i in "$@"; do
printf '%s\n' "$i"
done

7
scripts/printf.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
name="John"
printf "%s\nHello $name"
printf "\n"
printf "Open issues: %s\nClosed issues: %s\n" "34" "65"

7
scripts/prompt Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
# Opens a basic yes/no prompt with dmenu
# This is useful for confirming whether an action should be taken
if [ $(printf "No\nYes" | dmenu -i -p "$1") = "Yes" ]; then
$2
fi

15
scripts/python_script.sh Executable file
View file

@ -0,0 +1,15 @@
##!/bin/python3
#print("RUN THIS DIRECTLY FROM PYTHON!")
#!/bin/bash
python - <<'END_SCRIPT'
print("TESTPRINT")
END_SCRIPT
python -c 'print("ANOTHER_TEST_PRINT")'
python <<< 'print("YET_ANOTHER_TEST")'
echo "THIS IS BASH TALKING NOW"

5
scripts/python_update.py Executable file
View file

@ -0,0 +1,5 @@
from os import *
# This file is simply to demonstrate that utilizing python's native os module allows us to pass bash commands using the system() method.
system('sudo pacman -Syu')

7
scripts/reboot.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
if [ -d "$HOME/.recycle-bin" ] ; then
doas rm -r "$HOME/.recycle-bin/" && doas reboot
else
doas reboot
fi

17
scripts/remember Executable file
View file

@ -0,0 +1,17 @@
#!/bin/bash
# remember--An easy command line-based reminder pad
rememberfile="$HOME/.remember"
if [ $# -eq 0 ] ; then
# Prompt the user for input and append whatever they write to
# the rememberfile.
echo "Enter note, end with ^D: "
cat - >> $rememberfile
else
# Append any arguments passed to the script on to the .remember file.
echo "$@" >> $rememberfile
fi
exit 0

23
scripts/remindme Executable file
View file

@ -0,0 +1,23 @@
#!/bin/bash
# remindme--Searches a data file for matching lines or, if no
# argument is specified, shows the entire contents of the data file
rememberfile="$HOME/.remember"
if [ ! -f $rememberfile ] ; then
echo "$0: You don't seem to have a .remember file. " >&2
echo "To remedy this, please use 'remember' to add reminders" >&2
exit 1
fi
if [ $# -eq 0 ] ; then
# Display the whole rememberfile when not given any search criteria.
more $rememberfile
else
# Otherwise, search through the file for the given terms, and display
# the results neatly.
grep -i -- "$@" $rememberfile | ${PAGER:-more}
fi
exit 0

3
scripts/resolution Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
xdpyinfo | grep dimensions | sed -r 's/^[^0-9]*([0-9]+x[0-9]+).*$/\1/'

21
scripts/rpl Executable file
View file

@ -0,0 +1,21 @@
#!/bin/sh
#
# rpl: rpl str1 in files with str2, in place
PATH=/bin:/usr/bin
case $# in
0|1|2) echo 'Usage: replace str1 str2 files' 1>&2; exit 1
esac
left="$1"; right="$2"; shift; shift
for i # same as for $*
do
/home/brian/scripts/overwrite $i sed "s@$left@$right@g" $i
done
# $ cat footnote
# UNIX is not an acronym
# $ rpl UNIX Unix footnote
# Unix is not an acronym

19
scripts/scriptbc Executable file
View file

@ -0,0 +1,19 @@
#!/bin/bash
# scriptbc--Wrapper for 'bc' that returns the result of a calculation
# this script was taken from the Wicked Cool Shell Scripts book, page 35
if [ "$1" = "-p" ] ; then
precision=$2
shift 2
else
precision=2 # Default
fi
bc -q -l << EOF
scale=$precision
$*
quit
EOF
exit 0

3
scripts/serve Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
live-server --open="$1"

336
scripts/set_shopt.sh Executable file
View file

@ -0,0 +1,336 @@
##!/bin/bash
# The following scripts/notes are taken from the National Institute of Health's lecture series on the bash shell,
# and goes into detail about Shell Options, specifically the options defined by the set and shopt commands.
# You can find the introduction video here: https://www.youtube.com/watch?v=26t2LMtrDOc
# The Shell is defined by these elements:
# shell level (1, 2, 3)
# directolry location (pwd)
# set of defined variables (both regular and exported)
# set of procceses or jobs
# shell options
# Shell Options
# options are binary; either enabled or disabled
# disable accidental overwriting of files (noclobber) exiting the shell upon command failure (err exit)
# allowing recall of previously run commands (history)
# automatic notification of background job completion (notify)
# ... and many more
# Shell options are defined using set and shopt
# There are two sets of options, old (set) and new (shopt)
# All options defined by set can be configured using shopt as well
# set {+, -}o and shopt -o both display and configure the old options
# shopt displays and configures the new options
# Demonstration:
# Old Options (for now let's just see what is here, it looks like we have a series of options with a boolean on/off value)
# set -o
# prints:
# allexport off
# braceexpand on
# emacs off
# errexit off
# errtrace off
# functrace off
# hashall on
# histexpand on
# history on
# ignoreeof off
# interactive-comments on
# keyword off
# monitor on
# noclobber off
# noexec off
# noglob off
# nolog off
# notify off
# nounset off
# onecmd off
# physical off
# pipefail off
# posix off
# privileged off
# verbose off
# vi on
# xtrace off
# Let's see what happens when we invoke set with the +o argument:
# set +o
# prints:
# set +o allexport
# set -o braceexpand
# set +o emacs
# set +o errexit
# set +o errtrace
# set +o functrace
# set -o hashall
# set -o histexpand
# set -o history
# set +o ignoreeof
# set -o interactive-comments
# set +o keyword
# set -o monitor
# set +o noclobber
# set +o noexec
# set +o noglob
# set +o nolog
# set +o notify
# set +o nounset
# set +o onecmd
# set +o physical
# set +o pipefail
# set +o posix
# set +o privileged
# set +o verbose
# set -o vi
# set +o xtrace
# With +o, set displays all the old options using the command that will configure them to their current state.
# Just keep this in the back of your mind for now...
# Display new options
# shopt
# prints
# autocd on
# assoc_expand_once off
# cdable_vars off
# cdspell on
# checkhash off
# checkjobs off
# checkwinsize on
# cmdhist on
# compat31 off
# compat32 off
# compat40 off
# compat41 off
# compat42 off
# compat43 off
# compat44 off
# complete_fullquote on
# direxpand off
# dirspell off
# dotglob off
# execfail off
# expand_aliases on
# extdebug off
# extglob off
# extquote on
# failglob off
# force_fignore on
# globasciiranges on
# globstar off
# gnu_errfmt off
# histappend on
# histreedit off
# histverify off
# hostcomplete on
# huponexit off
# inherit_errexit off
# interactive_comments on
# lastpipe off
# lithist off
# localvar_inherit off
# localvar_unset off
# login_shell off
# mailwarn off
# no_empty_cmd_completion off
# nocaseglob off
# nocasematch off
# nullglob off
# progcomp on
# progcomp_alias off
# promptvars on
# restricted_shell off
# shift_verbose off
# sourcepath on
# xpg_echo off
# NOTE that you can display the old set -o options using shellopt -o as well (for some brevity's sake, I won't display the printed output here)
# shopt -o
# shopt -p -o (displays the same as the set +o command)
# Demonstration
# let's create a file that has important data:
# echo "really really important data" > file
# now let's say we accidentally overwrote that data:
# echo "just testing" > files
# as you can see, we just overwrote our really really important data with just testing...how can we use shopt to prevent us from accidentally overwriting this data?
# Well, the shell option noclobber can prevent us from overwriting files.
# set -o | grep noclobber
# prints:
# noclobber off
# And as you can see, the noclobber option is currently set to off, so let's enable it to prevent accidental file overwrites
# set -o noclobber
# set -o | grep noclobber
# prints:
# noclobber on
# To reverse this and turn it off, use the +o argument:
# set +o noclobber
# We also could have used shopt to do the same:
# shopt -s -o noclobber
# Now let's check to see if no clobber is now on:
# shopt -o noclobber
#prints:
# noclobber on
# So now let's test it:
# echo "again into the file" > file
#prints:
# bash: file: cannot overwrite existing file
# As you can see, setting the noclobber option to on using either the set -o noclobber or the shopt -o noclobber commands prevents
# us from accidentally overwriting our files from the command line.
# Another Example:
# Suppose you and your colleagues can't decide on a way of creating subdirectories:
# ls
# prints:
# file Project_1 PROJECT_2 project_3
# You can try to search for a certain directory using a lowercase p:
# ls -d *project_3
# prints:
# project_3
# This is obviously because bash by default reads everything with case sensitivity turned on (i.e. it delineates between upper and lower case) We can turn off this case insensitivity using shopt's nocaseglob option (set doesn't have this capability)
# shopt nocaseglob
# prints:
# nocaseglob off
# Ok, so let's turn the nocaseglob option on, this will turn off case-sensitivity in bash:
# shopt -s nocaseglob
# And let's check to be sure:
# shopt nocaseglob
# prints:
# nocaseglob on
# So now when we try the same search, it should include all project files regardless of upper or lower case:
# ls -d p*
# prints:
# Project_1 PROJECT_2 project_3
# One last example
# Imagine you absolutely must create a directory that begins with a hashtag (albeit there are very few situations where this would actually be necessary, but just run with it...)
# If we were to try to simply do that with bash's default settings:
# mkdir #_1
# prints:
# mkdir: missing operand
# Try 'mkdir --help' for more information.
# Obviously, this doesn't work because a hashtag is the beginning of a bash comment, and thusly bash interprets this as:
# mkdir
# With no following arguments, because it is reading it as commented out, the "_1" is a comment as far as bash is concerned.
# Luckily for us shopt has an option to turn this off.
# shopt -u interactive_comments
# Now we should be able to create such a directory:
# mkdir #_1
# ls -d #*
# should print (modern bash doesn't accept this):
# #_1
# As an aside, it is mentioned in the lecture to not do this, as using the hashtag character is extremely common and you might get yourself into trouble abandoning it
# Review
# Set, display, enable, and disable options:
# Set/Display:
# set {+,-}o
# set {+,-}o [option]
#Set/Enable/Disable
# set {+,-}?
# Shopt display, enable, and disable options:
# Shopt/Display:
# shopt [new option] #shopt options
# shopt -o [old option] # set options
# Shopt/Enable/Disable:
# shopt -u, -s [new option]
# shopt -u, -s -o [old option]
# Using set to turn debugging on/off
# set -x (turns debugger on)
# set +x (turns debugger off)
# NOTE: set/shopt options are always boolean on/off enabled/disabled. Options are only defined in the current shell (and shell session), and are NOT defined within subshells. Options are also only defined with the current working directory.
# More information about set and shopt can be found in the GNU man pages. Simply type man bash and search using /set or /shopt to jump to their respective sections.

7
scripts/shutdown.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/bash
if [ -d "$HOME/.recycle-bin" ] ; then
doas rm -r "$HOME/.recycle-bin/" && doas shutdown -h now
else
doas shutdown -h now
fi

9
scripts/source_functions.sh Executable file
View file

@ -0,0 +1,9 @@
# This file is meant to be exported, or otherwise known in bash as "sourced" in another file.
# We can simply define a function here called check_root() that when invoked will check to see if the file is being executed as root.
check_root() {
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
}

13
scripts/source_source.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
# Here we source/import the source_functions.sh file, which has a function called check_root() which checks
# to see if the file is being executed as root. If the file is executed by a non-root user, then the check_root() function
# let's the user know that the file must be executed as root and then exits with an error status of 1.
# If the user is root, the source_functions.sh file has no other code, but this file continues on to echo back at the user that
# "I am root"
source source_functions.sh
check_root
echo "I am root"

64
scripts/strings.sh Executable file
View file

@ -0,0 +1,64 @@
# There are many string methods in BASH. The following exemplify just a handful of them.
# Replace pattern in string.
a='I am a string'
echo "${a/a/A}"
# prints
# I Am a string
# Replace all matches of a pattern in a string.
echo "${a//a/A}"
# prints
# I Am A string
# Match the first character at the beginning.
echo "${a/#I/y}"
# prints
# y am a string
# Match a achater only at the end.
echo "${a/%g/N}"
I am a strinN
# Replace a pattern with nothing:
echo "${a/g/}"
#prints
# I am a strin
# Add a prefix to array items:
A=(hello world)
echo "${A[@]/#/R}"
# prints
# Rhello Rworld
# Section 15.4: Substrings and subarrays
var='0123456789abcdef'
# Define a zero-based offset
# Returns from after the third index:
printf '%s\n' "${var:3}"
# prints
# 3456789abcdef
# Offset and length of substring
printf '%s\n' "${var:3:4}"
# Negative length counts from the end of the string
printf '%s\n' "${var:3:-5}"
# prints
# 3456789a
# Also just prints from the end of the string if no second parameter is provided.
printf '%s\n' "$var: -6"
# prints
# abcdef
# you can also do the same with parentheses to be more concise:
printf '%s\n' "${var:(-6)}"

12
scripts/test.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/bash
my_number=$1
my_other_number=$2
# the test keyword can be used to return a true or false statement based off of what parameters we pass to it, generally speaking though, we won't get an output unless we explicitly place 'test' within an 'if' statement.
if (test "$my_number" != "$my_other_number"); then
echo "yeah, those are NOT equal!"
else
echo "nah, those two numbers are equal!"
fi

3
scripts/testjo Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
jo -p menu=$(jo id=file value=File popup=$(jo menuitem=$(jo -a $(jo value=New onclick="CreateNewDoc()") $(jo value=Open onclick="OpenDoc()")))) | jq

92
scripts/timein Executable file
View file

@ -0,0 +1,92 @@
#!/bin/bash
# timein--Shows the current time in the specified time zone or
# geographic zone. Without any argument, this shows UTC/GMT.
# Use the word "list" to see a list of known geographic regions.
# Note that it's possible to match zone directories (regions),
# but that only time zone files (cities) are valid specifications.
# Time zone database ref: http://www.twinsun.com/tz/tz-link.htm
zonedir="/usr/share/zoneinfo"
if [ ! -d $zonedir ] ; then
echo "No time zone database at $zonedir." >&2
exit 1
fi
if [ -d "$zonedir/posix" ] ; then
zonedir=$zonedir/posix # Modern Linux systems
fi
if [ $# -eq 0 ] ; then
timezone="UTC"
mixedzone="UTC"
elif [ "$1" = "list" ] ; then
(
echo "All know time zones and regions defined on this system:"
cd $zonedir
find -L * -type f -print | xargs -n 2 | \
awk '{printf " %-38s\n", $1, $2 }'
) | more
exit 0
else
region="$(dirname $1)"
zone="$(basename $1)"
# Is the given time zone a direct match? If so, we're good to go.
# Otherwise we need to dig around a bit to find things. Start by
# just counting matches.
matchcnt="$(find -L $zonedir -name $zone -type f -print |\
wc -l | sed 's/[^[:digit:]]//g')"
# Check if at least one file matches.
if [ "$matchcnt" -gt 0 ] ; then
# But exit if more than one file matches.
if [ $matchcnt -gt 1 ] ; then
echo "\"$zone\" matches more than one possible time zone record." >&2
echo "Please use 'list' to see all known regions and time zones." >&2
exit 1
fi
match="$(find -L $zonedir -name $zone -type f -print)"
mixedzone="$zone"
else # Maybe we can find a matching time zone region, ratgher than a specifications
# time zone.
# First letter capitlized, rest of word lowercase for region + zone
mixedreegion="$(echo ${region%${region#?}} \
| tr '[[:lower:]]' '[[:upper:]]') \
$(echo ${region#?} | tr '[[:upper:]]' '[[:lower:]]')"
mixedzone="$(echo ${zone%${zone#?}} | tr '[[:lower:]]' '[[:upper:]]') \
$(echo ${zone#?} | tr '[[:upper:]]' '[[:lower:]]')"
if [ "$mixedregion" != "." ] ; then
# Only look for specified zone in specified region
# to let users specify unique matches when there's
# more than one possibility (e.g., "Atlantic").
match="$(find -L $zondir/$mixedregion -type f -name $mixedzone -print)"
else
match="$(find -L $zonedir -name $mixedzone -type f -print)"
fi
# If file exactly matched the specified pattern
if [ -z "$match" ] ; then
# Check if the pattern was too ambiguous.
if [ ! -z $(find -L $zonedir -name $mixedzone -type d -print) ] ; then
echo "The region \"$1\" has more than one time zone. " >&2
else # Or if it just didn't produce any matches at all
echo "Can't find an exact match for \"$1\". " >&2
fi
echo "Please use 'list' to see all known regions and time zones." >&2
exit 1
fi
fi
timezone="$match"
fi
nicetz=$(echo $timezone | sed "s|$zonedir/||g") # Pretty up the output.
echo It\'s $(TZ=$timezone date '+%A, %B %e, %Y, at %l:%M %p') in $nicetz
exit 0

26
scripts/transcript.sh Executable file
View file

@ -0,0 +1,26 @@
#!/bin/bash
# This file is to demonstrate the more nuanced aspects of the trap command. Whenever the sigspec (signal code) is SIGTERM or SIGINT. It creates an infinitely counting loop until hte user hits CTRL+Z to end the process.
# SIGINT is a keyboard termination signal, usually by CTRL+C, but in this case it can only be stopped by CTRL+Z...
# SIGTERM is initiated when some other kind of intiator is intiated to terminate the signal, it usually stops the process first by closing teh running task/open file and then terminates the signal. This is sometiumes ignored.
# To know more about sigspecs, see: https://www.programmersought.com/article/81145757226/
# Set a trap for SIGINT and SIGTERM signals
trap "echo The program is terminated." SIGTERM SIGINT
#Display message to generate SIGTERM
echo "Press Ctrl+Z stop the process"
#Initialize counter variable, i
i=1
#declare infinite while loop
while :
do
#Print message with counter i
echo “running the loop for $i times”
#Increment the counter by one
((i++))
done

15
scripts/trap.sh Executable file
View file

@ -0,0 +1,15 @@
#!/bin/bash
touch temp.txt
# trap is a powerful command that allows us to chain an execution of commands AFTER a particular command is executed.
# to demonstrate this, we tell trap to hold onto the 'rm temp.txt' command, which removes the temp.txt file we just created above, note however, that it will only do that upon exit, as specified below.
trap 'rm temp.txt' err exit
# Now we will list all files in our directory to show that indeed, temp.txt still exists...
ls
# however, by running this program, we will then exit this shell, and thusly invoke the trap command above, if we invoke ls after invoking this shell script, you will notice that temp.txt no longer exists.
exit

View file

@ -0,0 +1,212 @@
Bash Scripting can be rather difficult at first, so these notes are an attempt to establish some basics in understanding. This won't go into too much details, but rather is a follow along of the most important takeaways from the https://guide.bash.academy/commands/ section thus far.
# A side note: you can append to the directories your bash shell looks for shell scripts by adding a :/path/to/shell_scripts to your $PATH in your .bashrc
A standard if statement that checks to see if you cannot remove hello.txt, and if not, then a message is sent to standard error(2), then the exit command is sent, and the if statement ends.
if ! rm hello.txt; then echo "Couldn't delete hello.txt." >&2; exit 1; file
A shorter version of the same command using the control operator (||):
rm hello.txt || { echo "Couldn't delete hello.txt." >&2; exit 1; }
Create a file called myfiles.ls if any standard output (1) is produced by the command ls, if not, and a standard error(2) is produced, then send the standard error output to a file in this directory(./) called myerrors.txt
ls >myfiles.ls 2>./myerrors.txt
Create a file called myfiles_or_myerrors.txt which takes the output of ls sermthing and creates that file with the output of either the successful standard output(1) or the standard error(2)
ls sermthing >myfiles_or_myerrors.txt 2>&1
Echo into a file called world in our home directory the phrase Hello(note that if world doesn't exist, it will be created)
echo Hello >~/world
If you wished to append to our world file above, rather than rewriting it, use the append (>>) syntax instaed of the write(>) syntax.
echo World >>~/world
cat world
Hello World
Take the results of ping 127.0.0.1 and write that to a file called results, whether it has a standard output(1) result or a standard error result(2)
ping 127.0.0.1 >results 2>&1
A shorter version of this would be written like so
ping 127.0.0.1 &>results
Assigning temporary variables in bash is as simple as using the equal syntax
name="Linus"
echo "Hello $(name)!"
Hello Linus!
We can also use curly braces to refer to this. echo "Hello ${name}!"
Hello Linus!
Let's say we wanted to only refer to what followed before or after a specific character, this can be done like so:
name="Britta" time=23.73
echo "$name's current record is ${time%.*} seconds and ${time#*.} hundredths."
Britta's current record is 23 seconds and 73 hundredths.
Another example is using it with letters to make this more clear:
echo "$name's name is ${name%i*} before the i and ${name#*i} after the i."
Britta's name is Br before the i and tta after the i.
Capitalize the first word of the variable greeting.
greeting="hello world"
echo "${greeting^}"
Hello world
Replace the first space character with the string " big "
greeting="hello world"
greeting="${greeting/ / big }"
echo $greeting
hello big world
Redirect the contents of $greeting into a filename of the same name, but with underscores(_) instaed of spaces( ) ending in .txt
greeting="hello big world"
echo $greeting > "${greeting// /_}.txt"
Show the contents of the variable greeting with the middle word fully upper-cased.
greeting="hello big world"
# Assigns the middle variable to everything before the last space.
middle="${greeting% *}"
echo $middle
hello big
# Reassigns the middle variable to everything in it currently, but everything after the first space is deleted.
middle="${middle#* }"
echo middle
big
# Now we can capitalize our middle word in the phrase like so:
echo "${greeting%% *} ${middle^^} ${greeting##* }"
hello BIG world
# Note the difference if we omit the double signs:
echo "${greeting% *} ${middle^^} ${greeting#* }"
hello big BIG big world
This is because the double percent(%%) and double hashtags(##) will double omit the spaces, meaning that it will omit the spaces as many times as there is %% or ##.
# To open a new bash shell and then output echo $1, where 'Hello World!' is passed in as the argument for $1
bash -c 'echo "$1"' -- 'Hello World!'
Hello World!
# To start a bash shell that takes in any number of arguments, and echos back the number of arguments passed.
bash -c 'echo "$#"' -- 1 2 'The Third'
3
# To start a bash shell that shifts a positional parameter away and then ouitputs the first, passing in arguments 1, 2, and The Third
bash -c 'shift; echo "$1"' -- 1 2 'The Third'
2
# To start a bashs hell that outputs the last argument passed in and pass in the arguments 1, 2, and The Third.
bash -c 'echo "${@: -1}"' -- 1 2 'The Third'
The Third
# Arrays
Arrays in bash are created using parentheses () braces. They can contain any files, variables, numbers, etc. They are separated by spaces and thusly, like a bash command, must be delineated using quotation marks "" in order to delineate specific files, especially when spaces are included in the filename. Here's an example:
files=( myscript hello.txt "05 Between Angels and Insects.ogg")
We can then access these elements in the array using the echo command like so:
echo "${files[0]}"
myscript
echo "${files[1]}"
hello.txt
echo "${files[2]}"
'05 Between Angels and Insects.ogg'
echo "${files[@]}"
myscript hello.txt '05 Between Angels and Insects.ogg'
# Note that the above can also be done by substituting @ with *, but because of how dangerous and "greedy" the * argument can be, it is best avoided in favor of @
# Note that if we just try to echo files, it will only return the first element of the array.
echo "$files"
myscript
We can also append(push) onto the array, as well as use a few other interesting array methods
files+=( self.png )
echo "${files[@]}"
myscript hello.txt '05 Between Angels and Insects.ogg' self.png
Assigns an array of all txt files to an array called files.
files=(*.txt)
Remove a specific element of an array
echo "${files[@]}"
myscript hello.txt '05 Between Angels and Insects.ogg' self.png
unset "files[3]"
echo "${files[@]}"
myscript hello.txt '05 Between Angels and Insects.ogg'
# As noted above the * argument is dubious and should always be used with caution, however in the example given above when comparing it with @, it is rather innocuous, and in certain situations where it is used for trivial purposes, it can be quite useful, such asi n the following example:
names=("Susan Quinn" "Anne-Marie Davis" "Mary Tate")
echo "Invites sent to: <$[names[*]]>."
Invites were sent to: <Susan Quinn Anne-Marie Davis Mary Tate>
# The following is interesting, the $IFS shell variable is usually set to a space, but in this case we set it to a comma. Note the opening parentheses without any equal operator, this indicates opening up what is called a "subshell" in which the global shell variable is changed within a localized SCOPE, and is only equivalent to the comma within the context of that scope (i.e. when the parentheses close)
( IFS=','; echo "invites sent to: <${names[*]}>." )
Invites were sent to: <Susan Quinn,Anne-Marie Davis,Mary Tate.>.
#### LEFT OFF AT THE END OF VARIABLES, STARTING NEXT AT TESTS AND CONDITIONALS ####
https://guide.bash.academy/conditionals/
#### CONDITIONALS ####
# Here let's just jump right in with a simple example of an if statement that evalutates user input:
read -p "Would you like some breakfast?[y/n]: "
Would you like some breakfast?[y/n]: (user inputs y)
echo $REPLY
y
# Now let's evaluate this with a simple if statement
if [[ $REPLY = y ]]; then
echo "Here you go, an egg sandwich"
else
echo "Here, you should at least have some coffee."
fi
# And of course the reponse is based off of whether the user passed y/n to the original read statement
# This can be chained so that the response is immediately evaluated upon response like so:
read -p "Breakfast?[y/n]: "; if [[ $REPLY = y ]]; then echo "Here you go, an egg sandwich"; else echo "Here, you shoudl at leats have some coffee."; fi
#### LOOPS ####
That's it for conditionals! (short chapter!)
Next up is Loops, which can be found at https://guide.bash.academy/loops
This section was not yet completed at the time of this writing, so instead we went to gokicker.com and picked up their Bash for Professionals free book pdf (see ~/Documents/Code/programming_books)
We picked up for loops at section 10.3:
A simple for loop can be displayed as such:
arr=(a b c d e f)
for i in "${arr[@]}" ; do
echo "$i"
done
# Continue on at 13.1 of Bash Notes for Professionals from GoalKicker.com

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,9 @@
Taken from stack overflow page when looking up how to list all aliases, found this:
compgen -c will list all the commands you could run.
compgen -a will list all the aliases you could run.
compgen -b will list all the built-ins you could run.
compgen -k will list all the keywords you could run.
compgen -A function will list all the functions you could run.
compgen -A function -abck will list all the above in one go.

View file

@ -0,0 +1,44 @@
array_methods.sh
associative_arrays.sh
bash_notes.txt
case_example.sh
crl
dirlist.txt
functions.sh
inpath
intro
jscurl_with_notes
left_off.txt
loops.sh
node_script.sh
normdate
parallel
python_script.sh
README.md
strings.sh
valida1num
variables.sh
# This file was generated using redirection, (page 41 of the bash.pdf). Because the file redirection was successful(status code 1), it created the above output from the ls command.
# ls > dirlist.txt 2>&1
# There are two syntactically more concise formats to this:
# ls &> dirlist.txt
# ls >& dirlist.txt
# You can also append using similar syntax, by simply adding another redirection operator character (>). The following would
yield an error output (see below).
# lsh &>> dirlist.txt
# lsh >>& dirlist.txt
########################
# The following was appended to demonstrate that standard error messages(2) will also be redirected when using the 2>&1 syntax:
# lsh >> dirlist.txt 2>&1
bash: lsh: command not found
# Just as an aside (because it's unlikely you'll need this syntax), the pipe operator (|) used in conjection with the redirection operator (>) will attempt to send the output of the command to the file even if the file exists.

View file

@ -0,0 +1,44 @@
Exports in Bash require a bit of a different mindset than other programming languages, but reflecting on how this works might also inform you on
how exporting works in other languages, so let's keep an open mind.
In bash we simply defign variables through assignment, like so:
myVar="my string"
echo $myVar
my string
Now let's say we open another bash instance by actually invoking the bash shell, then what happens if we try and reference $myVar?
bash # new bash instance
echo $myVar
# returns nothing
This is because we defined a localized variable to the particular shell session. Now, we could do a work around and in our bashrc outright define a new
variable so that whenever we invoke bash, the rc document is read and that is set for us, but that is a sort of cheat. The proper way to do this sort of thing (and probably useful in a variety of contexts, is to use the export keyword)
export myVar="my string"
bash
echo $myVar
my string
There are many options to this, here is the tldr documentation regarding export (tldr export):
Command to mark shell variables in the current environment to be exported with any newly forked child processes.
More information: https://www.gnu.org/software/bash/manual/bash.html#index-export.
Set a new environment variable:
export VARIABLE=value
Remove an environment variable:
export -n VARIABLE
Mark a shell function for export:
export -f FUNCTION_NAME
Append something to the PATH variable:
export PATH=$PATH: path/to/append
So we have a lot of options to keep in mind. This could possibly be useful in say, a tmux session.

103
scripts/unrm Executable file
View file

@ -0,0 +1,103 @@
#!/bin/bash
# unrm--Searches the deleted files archive for the specified file or
# diredctory. If there is m,ore than one matching result, it shows a list
# of results ordered by timestampe and lets the user specify which one
# to restore.
archivedir="$HOME/.recycle-bin"
realrm="$(which rm)"
move="$which mv"
dest=$(pwd)
if [ ! -d $archivedir ] ; then
echo "$0: No deleted files directory: nothing to unrm" >&2
exit 1
fi
cd $archivedir
# If given no arguments, just show a listing of the delted files.
if [ $# -eq 0 ] ; then
echo "Contents of your delted files archive (sorted by date):"
ls -FC | sed -e 's/\([[:digit:]][[:digit:]]\.\)\{5\}//g' \
-e 's/^/ /'
exit 0
fi
# Otherwise, we must have a user-specified pattern to work with.
# Let's see if the pattern matches more than one file or directory
# in the archive.
matches="$(ls -d *"$1" 2 > /dev/null | wc -l )"
if [ $matches -gt 1 ] ; then
echo "More than one file or directory match in the archive:"
index=1
for name in $(ls -td *"$1" )
do
datetime="$(echo $name | cut -c1-14) \
awk -F. '{ print "$5"/"$4" at "$3":"$2":"$1" }')"
filename="$(echo $name | cut -c16-)"
if [ -d $name ] ; then
filecount="$(ls $name | wc -l | sed 's/[^[:digit:]]//g')"
echo " $index) $filename (contents = ${filecount} items," \
" deleted = $datetime)"
else
size="$(ls -sdk1 $name | awk '{print $1}')"
echo " $index) $filename (size = ${size}Kb, deleted = $datetime)"
fi
index=$(( $index + 1 ))
done
echo ""
/bin/echo -n "Which version of $1 should I restore ('O' to quit)? [1] : "
read desired
if [ ! -z "$(echo $desired | sed 's/[[:digit:]]//g')" ] ; then
echo "$0: Restore canceled by user: invalid input." >&2
exit 1
fi
if [ ${desired:=1} -ge $index ] ; then
echo "$0: Restore canceled by user: index value too big." >&2
fi
if [ $desired -lt 1] ; then
echo "$0: Restore canceled by user." >&2
exit 1
fi
restore="$(ls -td1 *"$1" | sed -n "${desired}p")"
if [ -e "$dest/$1" ] ; then
echo "\"$1\" already exists in this directory. Cannot overwrite." >&2
exit 1
fi
/bin/echo -n "Restoring file \"$1\" ..."
$move "$restore" "$dest/$1"
echo "done."
/bin/echo -n "Delete the additional copies of this file? [y] "
if [ ${answer:=y} = "y" ] ; then
$realrm -rf *"$1"
echo "Deleted."
else
echo "Additional copies retained."
fi
else
if [ -e "$dest/$1" ] ; then
echo "\"$1\" already exists in this directory. Cannot overwrite." >&2
exit 1
fi
restore="$(ls -d *"$1")"
/bin/echo -n "Restoring file \"$1\" ..."
$move "$restore" "$dest/$1"
echo "Done."
fi
exit 0

118
scripts/unrm_with_notes Executable file
View file

@ -0,0 +1,118 @@
#!/bin/bash
# Very similar to our newrm command, we establish global variables that will be used throughout the program.
archivedir="$HOME/.recycle-bin" # variable that references our .recycle-bin directory
realrm="$(which rm)" # variable that references the rm binary
move="$which mv" # variable that references the mv binary
dest=$(pwd) # $dest variable that references our current working directory (i.e. the directory we are currently in)
if [ ! -d $archivedir ] ; then # if the .recycle-bin directory does NOT exist
echo "$0: No deleted files directory: nothing to unrm" >&2 # echo the message that it doesn't exist, and write the message to standard output
exit 1 # exit with an error status
fi
cd $archivedir # otherwise, change directory/cd into the .recycle-bin directory
# If given no arguments, just show a listing of the delted files.
if [ $# -eq 0 ] ; then # if the number of arguments passed is equal to zero...
echo "Contents of your delted files archive (sorted by date):" # echo this message...
# list all files that are appended and in columns (new lines), pipe this output to sed (stream editor command)
# which takes a (regular) expression (-e) expecting two digits followed by a period, up to the sixth (because of 0 indexing) position (globally)
# sed then takes another regular expression (-e) which then specifies any new line characters (s flag) that are not followed by an empty space.
# (remember that our ls flag -C puts the output in columns which is then fed to sed, hence this last regular expression allows sed to accept
# multiple arguments from the ls command.
ls -FC | sed -e 's/\([[:digit:]][[:digit:]]\.\)\{5\}//g' \ -e 's/^/ /'
exit 0 # and then exit with a success/OK status
fi
# Here we hold in the variable $matches the results of a subshell...
# Within the subshell, we invoke the ls -d command which lists all directories that match the first argument passed (file), the output of which is then sent to /dev/null
# The results of which are then piped to wc (word count, which then outputs the counted number of lines.
matches="$(ls -d *"$1" 2 > /dev/null | wc -l )"
# essentially, if the matched file within the .recycle-bin directory has ANY lines of content, then...
if [ $matches -gt 1 ] ; then
echo "More than one file or directory match in the archive:" # echo this message
index=1 # create a variable $index which starts at 1
for name in $(ls -td *"$1" ) # iterate over the results of ls -td, which takes all directories in .recycle-bin and sorts them by time created
do
# for all files that match the ls command, echo them into the $name variable established as the iterator,
# and cut the first through the 14th characters
datetime="$(echo $name | cut -c1-14) \
awk -F. '{ print "$5"/"$4" at "$3":"$2":"$1" }')" # and print out the remainder that is delineated by a '.' character
filename="$(echo $name | cut -c16-)" # and in the $filename variable, echo the $name again into cut, which takes the first 16 characters
if [ -d $name ] ; then # if there is a directory by the $name variable
filecount="$(ls $name | wc -l | sed 's/[^[:digit:]]//g')" # in a $filecount variable, hold the results of the subshell...
# which takes all files within the $name directory, counts the newline characters in them, and pipes that output of all files that are not appended with a number
# we then echo the index number (1) followed by the $filename, and its contents, as well as when the file was deleted
echo " $index) $filename (contents = ${filecount} items," \
" deleted = $datetime)"
# otherwise, if the $name is NOT a directory
else
# within the $size variable, hold the results of ls -sdk1, which takes the size, directory name, and k1(?) within the file $name,
# the results of the ls are piped to awk, which delineates by the first argument passed (the file you wish to restore)
size="$(ls -sdk1 $name | awk '{print $1}')"
# we then echo the index (1), the $filename, and the size of the file as well as the time it was deleted
echo " $index) $filename (size = ${size}Kb, deleted = $datetime)"
fi
# regardless of whether $name is a directory or not, we increase the index number until we run out of files/directories that match our first argument
index=$(( $index + 1 ))
done
echo "" # we then echo a blank line to delineate the next section
/bin/echo -n "Which version of $1 should I restore ('O' to quit)? [1] : " # we use the echo binary to ask the user which file to restore
read desired #and we create a variable, $desired, which will store the user input
if [ ! -z "$(echo $desired | sed 's/[[:digit:]]//g')" ] ; then # if the user passes a null value...
echo "$0: Restore canceled by user: invalid input." >&2 # echo the message and send it to standard output
exit 1 # and exit with an error status
fi
if [ ${desired:=1} -ge $index ] ; then # otherwise if the $desired variable is NOT null, but has a value greater than the index (total number of returned matches)...
echo "$0: Restore canceled by user: index value too big." >&2 # Let the user know that the index they chose is too large (it doesn't exist) and send the message to standard output
fi
if [ $desired -lt 1] ; then # very similar to the first if statement passed after read desired, checks for a negative number index essentially...
echo "$0: Restore canceled by user." >&2 # and assumes a cancellation by the user...
exit 1
fi
restore="$(ls -td1 *"$1" | sed -n "${desired}p")" # the filename is then restored to its original format using ls and sed
if [ -e "$dest/$1" ] ; then # if the file already exists within the destination directory...
echo "\"$1\" already exists in this directory. Cannot overwrite." >&2 # let the user know it already exists...
exit 1
fi
/bin/echo -n "Restoring file \"$1\" ..." # otherwise use the echo binary to let the user know that the program is restoring the file with the argument name...
$move "$restore" "$dest/$1" # and uses the mv binary to take the reformatted $restore file to the destination directory...
echo "done." # and lets the user know when it is done.
/bin/echo -n "Delete the additional copies of this file? [y] " # then the user is prompted by the echo binary (-n means no newline) if they want to delete all other copies of the file...
if [ ${answer:=y} = "y" ] ; then # if the user answers y...
$realrm -rf *"$1" # then the rm binary is invoked and the remaining files that match the argument within the current directory are deleted...
echo "Deleted." # and the user is notified as such.
else
echo "Additional copies retained." # otherwise, the user wishes to keep the remaining files, and we let them know we left the remaining files alone.
fi
# otherwise, if the returned search results has no content found...
else
if [ -e "$dest/$1" ] ; then # if the passed directory/file exists...
echo "\"$1\" already exists in this directory. Cannot overwrite." >&2 # let the user know you can't overwrite an existing file..
exit 1 # and exit with an error message
fi
restore="$(ls -d *"$1")" # and within the $restore variable, store the ls -d results of all files within a matching directory
/bin/echo -n "Restoring file \"$1\" ..." # use the echo binary to let the user know you are restoring the requested file....
$move "$restore" "$dest/$1" # and the mv binary is used to move the matched file to the current destination as the passed argument (it is renamed the passed argument)
echo "Done." # and the user is told when the process is done.
fi
exit 0 # and we exit with a success/OK status

33
scripts/valida1num Executable file
View file

@ -0,0 +1,33 @@
#!/bin/bash
# validAlphaNum--Ensures that input consists only of alphabetical
# and numeric characters
validAlphaNum()
{
# Validate arg: returns 0 if all upper+lower+digits; 1 otherwise
# Remove all unacceptable chars.
validchars="$(echo $1 | sed -e 's/[^[:alnum:]]//g')"
if [ "$validchars" = "$1" ] ; then
return 0
else
return 1
fi
}
# BEGIN MAIN SCRIPT--DELETE OR COMMENT OUT EVERYTHING BELOW THIS LINE IF
# YOU WANT TO INCLUDE THIS IN OTHER SCRIPTS.
# =================
/bin/echo -n "Enter input: "
read input
# Input validation
if ! validAlphaNum "$input" ; then
echo "Please enter only letters and numbers" >&2
exit 1
else
echo "Input is valid."
fi
exit 0

28
scripts/variables.sh Executable file
View file

@ -0,0 +1,28 @@
#!/bin/bash
# Variable assignment is rather straightforward in bash
name="brian"
echo $name
# prints:
# brian
# If we want to assign a number to a variable, we want to encase it within a subshell:
my_number=$((1))
echo $my_number
# prints
# 1
# Let's say we wanted to add to that number now, we could do that like so:
my_number=$(($my_number + 1))
echo $my_number
# prints
# 2
# Let's say we wanted to continually add to a number up to ten within a for loop:
for (( i=0; i<=10; i++ )); do
echo "$name's current number is: $i"
done

3
scripts/xh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
# chromium --incognito https://xhmaster.com/search/"${1}" &
librewolf https://xhmaster.com/search/"${1}" &