# ____ _ _ _
# / ___|| |__ ___| | |
# \___ \| '_ \ / _ \ | |
# ___) | | | | __/ | |
# |____/|_| |_|\___|_|_|
#
Here is a nice introduction to shell. It explains what they are, what differentiates them from the command line, and the different varieties of shell available.
Here is where I write a nice introduction about the Bourne again shell.
Here is my page to the wiki page for bash –> bash
Here is where I take a stab at explaining what ZSH is, and why zsh differs from bash.
Here is my page on zsh –> zsh
This section is to cover neat tricks that are too cool to be tucked away in a section of their own.
cat <<EOF> $FILE
> #!/usr/bin/env bash
> echo "Do something really cool!"
> EOF
While performing some server configuration work, this convenient script was written to make copying the configuration file over and restarting the server more convenient. It’s importance is the simple conditional that requires a user to have SuperUser Privileges in order to run. Appropriate slang included for variety.
#!/usr/bin/env bash
HTTPDIR="/etc/httpd.conf.d"
REPODIR="/local/location/of/files"
if [ "$EUID" -ne 0 ]; then
echo "Yo! You gotta be root to run this shit! Fool!"
echo "Try using sudo."
exit
else
echo "Nice, Playa! Word to your momma."
sleep 1
fi
UFILE="$REPODIR/$1"
SFILE="$HTTPDIR/$1"
if ! [[ -f "$UFILE" ]]; then
echo "Argument must be a configuration file located in $REPODIR"
exit
fi
USUM=$(cat "$UFILE" | md5)
SSUM=$(cat "$SFILE" | md5)
if [[ "$USUM" == "$SSUM" ]]; then
echo "Both files are the same."
exit
else
if [[ "$UFILE" -nt "$SFILE" ]]; then
echo "Replacing httpd configuration file and reloading server"
cp "$UFILE" "$SFILE"
rcctl restart httpd
echo "Done."
else
if [[ "$SFILE" -nt "$UFILE" ]]; then
echo "Replacing file in repository."
cp "$SFILE" "$UFILE"
chown "$USER" "$UFILE"
chmod 0755 "$UFILE"
echo "Done"
fi
fi
fi
This script is worth taking notice, because parts of it have been used numerous times in other scripts to aid in launching applications, and ensuring those applications remain running. This particular script just comes with an additional feature, which is to continuously check configuration files for changes.
#!/usr/bin/env bash
# Variables
CONFIG="$HOME/.config/hypr/waybar"
WAYCONFIG="$CONFIG/config"
WAYSTYLE="$CONFIG/style.css"
# start waybar if not started
if ! pgrep -x "waybar" > /dev/null; then
hyprctl keyword exec waybar -b "bar" --config "$WAYCONFIG"
fi
# current checksums
current_checksum_config=$(md5sum "$WAYCONFIG")
current_checksum_style=$(md5sum "$WAYSTYLE")
# loop forever
while true; do
# new checksums
new_checksum_config=$(md5sum "$WAYCONFIG")
new_checksum_style=$(md5sum "$WAYSTYLE")
# if checksums are different
if [ "$current_checksum_config" != "$new_checksum_config" ] || [ "$current_checksum_style" != "$new_checksum_style" ]; then
# kill waybar
killall waybar
# start waybar
waybar &
# update checksums
current_checksum_config=$new_checksum_config
current_checksum_style=$new_checksum_style
fi
done
Just a basic example of using case in bash.
case "$1" in
start | up)
vagrant up
;;
*)
echo "Usage: $0 {start|stop|ssh}"
;;
esac
This example was directly taken from a deprecated script once used to launch a remote desktop session using one of several methods.
while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case "$1" in
-a | --autossh )
run_autossh
;;
-s | --ssh )
RUN_HYPR=false
run_ssh
;;
-r | --hypr )
RUN_HYPR=true
run_ssh
;;
-k | --kill )
kill_all
;;
-v | --vnc )
"$VNC_CMD"
;;
_)
run_ssh
;;
esac; shift; done
if [[ "$1" == '--' ]]; then shift; fi
This is a snippet of a script that will download the latest release of an application.
#!/usr/bin/env bash
PROFILE=""
PROJECT=""
OUTFILE=""
ENDFILE=""
VERSION=$(curl -s "https://api.github.com/repos/$PROFILE/$PROJECT/releases/latest" | \grep -Po '"tag_name": *"v\K[^"]*')
curl -Lo "$OUTFILE" "https://github.com/$PROFILE/$PROJECT/releases/download/v${VERSION}/$PROJECT_${VERSION}_Linux_x86_64.tar.gz"
tar xf $OUTFILE $ENDFILE
sudo install $ENDFILE -D -t /usr/local/bin/
This takes part of the snippet above and actually integrates it into a working example of upgrading godns. It first checks to see if the current version and the current release are the same, if so nothing is done, if not so it downloads and installs the newest release.
Quite easily actually.
find /some/path \(-type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/some_phrase/some_replacement/g'
ssh otherhost << EOF
ls some_folder;
./someaction.sh 'some params'
pwd
./some_other_action 'other params'
EOF
HOST='your_sftp_server'
USER='your_username'
PASSWORD='your_password'
LOCAL_FILE='/path/to/local/file.txt'
REMOTE_DIR='/path/to/remote/directory/'
sftp $USER@$HOST <<EOF
put $LOCAL_FILE $REMOTE_DIR
bye
EOF
Recently a few new commands have been encountered, that have never been seen before, or I have seen and didn’t care to investigate. Either way, they listed below to help me remember them for later.
Newgroup allows a user to initiate and finalize changes to group membership without having to log out and in again. This feature becomes handy when the user does not need to lose any established environment variables.
Both Bash and Zsh provide a virtual directory stack used to aid navigation through complex paths. The utilization of this stack
is performed with the pushd command, the removal of entries from this stack is performed with the popd command, and the viewing of this
stack is performed with the dirs command. Each are discussed more fully below.
Pushd is a built in shell command that is known to come with both bash and zsh, Perl also has an implementation
for convenience. Pushd is designed to ease navigation of complex paths by adding those paths to an internal virtual stack.
Adding a path to the network stack places the path on top of the stack, meaning it will be positioned first, and first used
when pushd is used again. At anytime the user can view this stack by executing the dirs -l -v command. Which will provide
the user with a numbered list of paths which represents the virtual directory stack.
>~ dirs -l -v
0 /home/user
1 /
2 /home/user
3 /home/user/.emacs.d/init.d
4 /home/user/Projects
5 /home/user/Projects/clifm
6 /home/user/Downloads
7 /home/user/Projects/The_Duck
8 /home/user/Projects/vnc
9 /home/user/Projects/Scripts
10 /home/user/Projects/texstudio/build
11 /home/user/Projects/texstudio
12 /home/user/Projects/Wireguard
13 /home/user/Projects/GameBoy
14 /home/user/Projects/latex-work
15 /home/user/Documents/Risc-V/docs
Using pushd ${SOME-DIRECTORY} will change directory to ${SOME-DIRECTORY} AND add that directory to the top of the virtual
directory stack. If you issue pushd -n ${SOME-DIRECTORY} pushd with the -n flag, the directory will only be “pushed” to
the top of the directory stack, and your current directory will remain the same.
As it’s purpose would suggest, the user can fully utilize this virtual directory stack and navigate to any path in the stack by
issuing a pushd +{SOME-NUMBER} or pushd -{SOME-NUMBER}, where {SOME-NUMBER} is the “Nth” path in the stack. Using a “+”
(plus or positive symbol) will count upward from the bottom of the stack to the “Nth” entry, and using a “-“ (minus or negative
symbol) prefix will count downward from the top of the stack. Thus, referencing the example stack above, pushd +3 will change
directory to /home/user/.emacs.d/init.d, and pushd -3 will change directory to /home/user/projects/GameBoy.
Popd operates in much the same manner as pushd does, except rather than add paths to the directory stack, popd removes them. So,
similar to pushd, popd ${SOME-DIRECTORY} changes directory to ${SOME-DIRECTORY}, and then removes that directory from the directory
stack. Use of the -n flag will only remove the directory from stack, and use of “+/-“ will allow the user to remove the “Nth”
directory, and not change directory as well.
Compgen can be used to list every command available within a shell. As expected, the output of this command can be manipulated with flags, which is discussed below.
compgen -c outputs all available commands.compgen -a outputs all available aliases.compgen -b outputs all available shell builtin commands.compgen -k will output all keywords.compgen -A for all functions.I have seen this command thousands of times, but never considered including it in my own scripts until now,
and it really is incredible. Test simplifies and reduces the complexity of scripts by handling the “if…then” clause for you.
So, instead of having to write the entire block to test an expression, you can simply run test $EXPRESSION
and if it is true it will return not return anything, but if it is false it will return “1”. Examine the
example below.
# Long format
if [[ -e "/var/www/htdocs" ]]; then
echo "Geronimo!!!"
fi
# Now with test
test -e /var/www/htdocs