Creating Reusable Bash Scripts

Search for a command to run...

Great post, Waylon really cool Markdown hack for showing the social buttons below the post. ๐

I might need to tweak it just a bit, for some reason they aren't centered as well as they are on DEV
I will check the styling. Waylon
Is there a better way to do such things in hashnode. I have not really had enough time to fully digest everything yet, very busy week here.
I notice for instance that Catalin Pit has a newsletter signup. at the top of his.
Catalin is using an iFrame HTML tag inside markdown with some CSS styling. You can try it out.
True! It was one of his feedback and we implemented it on priority. :D Waylon
I've slowly adding more and more lua functions into my neovim configuration, and recently I noticed a pattern for a class of functions that reach out to run shell commands that can be abstracted away. https://youtu.be/8m5ipBuopPU Telegraph.nvim Check...

Kedro can have a chatty logger. While this is super nice in production so see everything that happened during a pipeline run. This can be troublesome

In 2021 I changed the way I navigate between tmux sessions big time. Now I can create, kill, switch with ease, and generally keep work separated into
People who are quick to toss team members under a bus are not well trusted or highly thought of and it will lead to some toxic team dynamics. Building Steam While collaborating on any project there are going to be decisions made that aren't necessari...

I create this blog with one person in mind, me. There are others like me This is not completely selfish, as there are likely many others out there that think similarly to me. Everyone comes from different backgrounds and varying levels of experience...

Bash is a language that is quite useful for automation no matter what language you write in. Bash can do so many powerful system-level tasks. Even if you are on windows these days you are likely to come across bash inside a cloud VM, Continuous Integration, or even inside of docker.
I have three techniques that help me write more composable bash scripts.
Break scripts down into reusable components
Functions in bash are quite simple. They are something that I wish I would have started using long ago. They make your code much more reusable. I often use them in my aliases as well since they can simplify the process and allow more flexibility.
syntax
#!/bin/bash
# hello_world.sh
hello_world () {
echo "hello world"
}
Source the file to load the function and run it from the terminal.
run it
source hello_world.sh
hello_world
outputs
hello world
Make functions a little more flexible
Arguments and options are quite a bit more complex in bash. For now, we will focus on the basics which are not all that bad.
easiest and most common to use
Positional arguments can be pulled out quite easily using $1 for the first one, $2 for the second, and so on.
note $0 is the command that was called. You will see this often used to find the command called to open up your current shell.
syntax
#!/bin/bash
# hello.sh
hello () {
echo "hello $1"
run it
source hello.sh
hello Waylon
Now we have a function that accepts positional arguments and we can call it by passing things into it.
outputs
hello Waylon
More than one argument would be ignored since we are only looking at $1.
run it
source hello.sh
hello Waylon Walker
outputs
hello Waylon
Just the same as before since we do not use the second argument.
Bash has another special variable $@ that stores all arguments in one.
syntax
#!/bin/bash
# hello.sh
hello () {
echo "hello $@"
}
Just the same as before.
run it
source hello.sh
hello Waylon Walker
Now the function will output all arguments that are passed into it since we are using the $@ variable.
outputs
hello Waylon Walker
Super powers in a single line
The easiest and most common way to handle an error in bash is through the use of the logical operators && (and) and || (or).
Here I have a concrete example from earlier today. I was creating a bash script to run a python script from cron. The bash script is there to make sure that we have the python environment, activate it, and run. If it doesn't have it, it should create it.
# creates the conda environment
create_env() {
conda create -n $1 python=3.8
conda activate $1
pip install -r requirements.txt
}
# checks if the conda environment exists
env_exists() {
conda info --envs | awk '{print $1}' | tail -n +3 | grep -w $1 > /dev/null
}
# creates the conda environment if it doesn't exist
# ๐ This is the meat of the error handling section ๐
create_if () {
env_exists $1 && echo "environment exists" || create_env $1
}
# ๐ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ ๐
create_if my_env
If we look at the create_if function, it will check if the environment exists if there is a passing status code 0, then it will run echo "environment exists" otherwise it will run create_env $1.
note Inside of env_exists grep will look for whole words if there is a match it will give a status code 0 if it finds a match and not 0 if there is no match.
_if __name__ == " __main__"_
The last thing I want to discuss is making a bash script both runnable and sourceable. This makes it so that you can source filename.sh and run each function individually, or bash filename.sh to run the script. This is a similar concept to if __name__ == " __main__" from python.
I did try this from bash and zsh with success. The following is an example that would pass all arguments into a main function.
syntax
if [["${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
Extending the example above that created a python example if necessary we can create the env if necessary, activate the environment, and run the script.
syntax
if [["${BASH_SOURCE[0]}" == "${0}" ]]; then
create_if my_env
conda activate my_env
python script.py
fi
Using this syntax to run our "main" functions will allow us to both runs the script or source the script to utilize the functions that we created.
| I have been writing short snippets about my mentality breaking into the tech/data industry in my newsletter, ๐ check it out and lets get the conversation started. | |||||
|
|||||
| ๐ see an issue, edit this post on GitHub |